{
  "bundles": [
    {
      "@type": "NXBundle",
      "artifactId": "nuxeo-diff-content",
      "artifactVersion": "2023.25.10",
      "bundleGroup": {
        "@type": "NXBundleGroup",
        "bundleIds": [
          "org.nuxeo.diff.content",
          "org.nuxeo.diff.core",
          "org.nuxeo.diff.jsf"
        ],
        "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff",
        "id": "grp:org.nuxeo.diff",
        "name": "org.nuxeo.diff",
        "parentIds": [
          "grp:org.nuxeo.ecm"
        ],
        "readmes": [
          {
            "blobProviderId": "default",
            "content": "# Nuxeo Diff\n\nThis repo hosts the source code of a plugin for Nuxeo Platform that allows to render a diff between two documents or two versions of a document.\nThe comparison takes into account all the properties shared by the documents, which means that if a comparison is done between two documents of a different type, only the schemas in common will be \"diffed\".\nThe comparison also takes into account blob-type properties.\n\n\n## Building and deploying\n\n    mvn clean install\n\n## Deploying\n\nInstall [the Nuxeo Diff Marketplace Package](https://connect.nuxeo.com/nuxeo/site/marketplace/package/nuxeo-diff).\n\n## Configuring\n\n### Diff display\n\nThe `DiffDisplayService` offers several extension points to configure the document diff display.\nMost of the code samples exposed here can be found in the [diff-display-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-display-contrib.xml) and [diff-widgets-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-widgets-contrib.xml) files.\n\n#### Configuring groups of properties to display with the diffDisplay extension point.\n\nA `diffDisplay` contribution represents a number of `diffBlocks` that you want to display when asking for a document comparison.\nIt is bound to a document type.\nA `diffBlock` contribution represents a number of properties (fields) that you want to display (see next section).\n\nWhen asking for the comparison between 2 versions of a document, the `diffDisplay` bound to the document type or a super type is used.\nIf no `diffDisplay` is found for this type or a super type a fall back is done on the default diff display mode: one block per document schema and for each block all the fields of the schema that are different.\n\n*Beware that in this case the order of the schemas and of the fields is undefined.*\n\nWhen asking for the comparison between 2 documents:\n- If they are of the same type: if  a `diffDisplay` is found for this type or a super type then it is used, else a fall back is done on the default diff display mode.\n- If they are of different types: if  a `diffDisplay` is found for a common super type then it is used, else a fall back is done on the default diff display mode.\n\nFor example, this is the `diffDisplay` contribution bound to the _File_ type:\n```xml\n<diffDisplay type=\"File\">\n  <diffBlocks>\n    <diffBlock name=\"heading\" />\n    <diffBlock name=\"dublincore\" />\n    <diffBlock name=\"files\" />\n  </diffDisplay>\n</diffBlocks>\n```\n\n_Note that the order of the diffBlocks is taken into account when rendering the diff display._\n\n#### Configuring a group of properties to display with the diffBlock extension point\n\nA `diffBlock` contribution represents a number of `fields` that you want to display. It is rendered as a foldable box.\nThe `label` attribute of a `diffBlock` contribution is used as the title of the foldable box.\nA `field` is defined by its `schema` and its `name`.\n\nFor example, this is the \"heading\" `diffBlock` contribution:\n```xml\n<diffBlock name=\"heading\" label=\"label.diffBlock.heading\">\n  <fields>\n    <field schema=\"dublincore\" name=\"title\" />\n    <field schema=\"dublincore\" name=\"description\" />\n  </fields>\n</diffBlock>\n```\n_Note that the order of the fields is taken into account when rendering the diff block._\n\nFor complex properties, you can contribute inside the `field` element the property `items` that you want to display:\n```xml\n<field schema=\"complextypes\" name=\"complex\">\n  <items>\n    <item name=\"stringItem\" />\n    <item name=\"thirdItem\" />\n    <item name=\"fourthItem\" />\n  </items>\n</field>\n```\n\n_Note that the order of the items is taken into account when rendering the field._\n\nThis is used for the `files` field of the `files` diff block:\n```xml\n<field schema=\"files\" name=\"files\">\n  <items>\n    <!-- Display the file only, not the filename which is managed\n         by the file widget type -->\n    <item name=\"file\" displayContentDiffLinks=\"true\" />\n  </items>\n</field>\n```\n\nIf no `items` are specified, all the property items are displayed.\n\nFor content properties (that hold a blob) or string ones you can set the `displayContentDiffLinks` attribute to `true` on a `field` or an `item` to display the content diff links.\nThese links will open a fancybox showing the detailed content diff using the usual green and red colors to distinguish the added/removed parts of the content.\nFor now, 2 links are displayed: _Textual diff_ based on a text conversion and _Html diff_ based on an html conversion (keeps the content layout).\n\n#### Configuring property widgets with the widgets extension point\n\n##### Principle\n\nWhen rendering a `diffBlock`, the `DiffDisplayService` builds a layout definition on the fly, including a layout row for each `field` of the `diffBlock`.\nEach row contains a widget definition for the `field`, and the layout template renders 2 instances of this widget definition: one for the left document and one for the right document.\nThe content diff links, if displayed, are also rendered by a widget inside the layout row.\n\nHow is the widget definition built for a given `field`?\nA lookup is done in the `LayoutStore` service to find a specific widget definition named with the xpath of the property.\nIf such a definition is not found, a lookup is done to find a generic widget definition named with the type of the property.\n\nThis allows you to only contribute a specific widget definition if the generic one doesn't match your needs for a given field, typically if you need a custom template, label or custom properties.\n\n##### Example\n\nLets say we have contributed the following `diffBlock`:\n```xml\n<diffBlock name=\"myCustomBlock\" label=\"label.diffBlock.custom\">\n  <fields>\n    <field schema=\"file\" name=\"content\" />\n    <field schema=\"dublincore\" name=\"title\" />\n  </fields>\n</diffBlock>\n```\n\nand the following widgets to the `widgets` extension point of the `org.nuxeo.ecm.platform.forms.layout.LayoutStore` component:\n```xml\n<extension target=\"org.nuxeo.ecm.platform.forms.layout.LayoutStore\"\n  point=\"widgets\">\n\n  <widget name=\"file:content\" type=\"file\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <labels>\n      <label mode=\"any\">label.summary.download.file</label>\n    </labels>\n    <translated>true</translated>\n    <properties mode=\"any\">\n    </properties>\n  </widget>\n\n  <widget name=\"string\" type=\"template\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <properties mode=\"any\">\n      <property name=\"widgetType\">text</property>\n      <property name=\"template\">\n        /widgets/generic_diff_widget_template.xhtml\n      </property>\n    </properties>\n  </widget>\n\n</extension>\n```\n\nWhen rendering the \"myCustomBlock\" `diffBlock`, the `DiffDisplayService` will:\n\n- Look for a specific widget definition named \"file:content\" in the `LayoutStore`, find it and use it for the \"file:content\" field.\n\n- Look for a specific widget definition named \"dublincore:title\" in the `LayoutStore`, won't find it and therefore will look for a generic widget definition named with the field type, ie. \"string\", find it and use it for the dublincore:title field.\n\nIn this use case, the \"string\" generic widget definition is sufficient to display the \"dublincore:title\" field.\nIt uses a widget of type \"text\" with \"label.dublincore.title\" as a label and \"dublincore:title\" as a field definition.\nWe can easily understand here the interest of generic widgets: once you have the type and xpath of a property, the matching widget definition can be computed on the fly using the property type to guess the widget type (\"string\" => \"text\", \"date\" => \"datetime\", etc.) and the property xpath for the field definition and label.\n\nThe \"file:content\" specific widget definition is contributed here to use a custom label \"label.summary.download.file\" instead of the one that would have been generated for the \"content\" generic widget definition: \"label.file.content\".\n\n_Note that in both cases (generic and specific) you don't need to define the widget field definitions since they are automatically computed from the property xpath, except in particular cases like \"note:note\" where the \"mime-type\" field is needed._\n\n##### List and complex properties\n\nYou might already know that the widgets used to display list and complex properties have subwidgets.\nIn the case of a list property, a subwidget is needed for the list items; in the case of a complex property, a subwidget is needed for each item of the complex property.\nThe lookup done by the `DiffDisplayService_` for the first-level widgets is also done recursively for the subwidgets!\n\n###### List property\n\nFor a list property, lets take the example of \"dublincore:contributors\", which is a string list.\n\n- To display the list, nothing special is needed so the \"scalarList\" generic widget definition can be used.\n\n- To display a list item (a contributor, which is of type \"string\"), the \"string\" generic widget definition doesn't match our needs: it would display the contributor's username whereas we want to display its fullname (firstname lastname).\nSo we need a specific widget definition for the list items subwidget to use a custom template able to display the contributor's fullname.\nThe name of this widget definition must match the xpath of the list item property, ie. \"dublincore:contributors/item\".\n\nTherefore, two widget definitions are involved:\n\n- The \"scalarList\" generic widget definition:\n\n```xml\n<widget name=\"scalarList\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"displayAllItems\">false</property>\n    <property name=\"displayItemIndexes\">true</property>\n    <property name=\"template\">\n      /widgets/list_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"dublincore:contributors/item\" specific widget definition:\n\n```xml\n<widget name=\"dublincore:contributors/item\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.dublincore.contributors.item</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"template\">/widgets/contributors_item_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n###### Complex property\n\nFor a complex property, lets take the example of a \"complextypes:complex\" property with two items \"stringItem\" and \"directoryItem\".\n\"stringItem\" is a simple string, but \"directoryItem\" is a string that needs to be bound to the \"myDirectory\" directory.\n\n- To display the complex property, nothing special is needed so the \"complex\" generic widget definition can be used.\n\n- To display the \"directoryItem\" item, the \"string\" generic widget definition doesn't match our needs: it would display the directory entry code stored in the backend whereas we want to display its label.\nSo we need a specific widget definition for the \"directoryItem\" subwidget to use the \"selectOneDirectory\" widget type bound to the \"myDirectory\" directory.\nAs for a list item, the name of this widget definition must match the xpath of the complex property item, ie. \"complextypes:complex/directoryItem\".\n\nTherefore, two widget definitions are involved:\n\n- The \"complex\" generic widget definition:\n\n```xml\n<widget name=\"complex\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"template\">\n      /widgets/complex_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"complextypes:complex/directoryItem\" specific widget definition:\n\n```xml\n<widget name=\"complextypes:complex/directoryItem\" type=\"selectOneDirectory\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.complextypes.complex.directoryItem</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"directoryName\">myDirectory</property>\n    <property name=\"localize\">true</property>\n    <property name=\"ordering\">ordering,label</property>\n  </properties>\n</widget>\n```\n\n###### Useful widget properties\n\nYou can use the following properties on a list widget definition (typically \"scalarList\", \"complexList\" or \"files:files\"):\n\n`<property name=\"displayAllItems\">[true|false]</property>`\nIf set to `true`, all the list items will be displayed, otherwise only the different ones will be.\n\n`<property name=\"displayItemIndexes\">[true|false]</property>`\nIf set to `true`, a subwidget will be added to the widget definition to display the list item indexes.\n\nYou can use the following property on a complex widget definition (typically \"complex\"):\n\n`<property name=\"display\">[inline|*]</property>`\nIf set to `inline` the complex items will be displayed as a table with one line and one column per item, otherwise as a table with one column and one line per item.\n\n##### About the value bound to the diff widgets\n\nIf you take a look at [layout_diff_template.xhtml](nuxeo-diff-jsf/src/main/resources/web/nuxeo.war/layouts/layout_diff_template.xhtml), you will see that the `value` passed to the `<nxl:widget>` tag is `#{value.leftValue}` or `#{value.rightValue}`, `value` being the object passed to the `<nxl:layout>` tag `value` attribute: `diffDisplayBlock`, of type `DiffDisplayBlockImpl`.\nThe `leftValue` and `rightValue` members of `DiffDisplayBlockImpl` are of type `Map<String, Map<String, PropertyDiffDisplay>>`. The first level Map keys are schema names, the second level ones are field keys.\nFinally, the `PropertyDiffDisplay` object has two members: `value` and `styleClass`, `value` holding the value to display and `styleClass` the css style class to apply to the &lt;span&gt; wrapping the value.\n\nFor example if we compare two documents where only the \"dublincore:title\" property is different (\"My first doc\" and \"My second doc\") we could have the following `diffDisplayBlock` object:\n\n```java\ndiffDisplayBlock.getLeftValue() = {dublincore={title={value=\"My first doc\", styleClass=\"redBackgroundColor\"}}}\ndiffDisplayBlock.getRightValue() = {dublincore={title={value=\"My second doc\", styleClass=\"greenBackgroundColor\"}}}\n```\n\nOn the widget side, the field definitions must match the `diffDisplayBlock` object structure, that's why the generated field definitions of the widget used for \"dublincore:title\" would be:\n\n```xml\n<fields>\n  <field>dublincore:title/value</field>\n  <field>dublincore:title/styleClass</field>\n</fields>\n```\n\nThis is important to know when designing a custom template for a diff widget (ie. where field definitions are automatically generated): you can use `#{field_0}` for the value itself and `#{field_1`} for the css style class associated to the value.\nBy default, only the items of a complex property or of a list property where the `displayAllItems` widget property is `true` can have a styleClass equal to `redBackgroundColor` or `greenBackgroundColor` in order to highlight the different items among all.\n\n#### To summarize: what you need to contribute to have a nice diff result for your custom document types\n\n- A `diffDisplay` contribution for each document type.\n\n- The associated `diffBlock` contributions. Don't forget that you can specify the items you want to display for a complex property and the fields/items for which you want to display the content diff links.\n\n- The specific widgets needed when the generic ones don't match your needs. Typically for a date property if you need to change the date format, or for a property bound to a directory to specifiy the directory name. Also don't forget that you can contribute a specific widget for a complex property item or a list item, using the item xpath.\n\n- The labels for each `diffBlock`, each widget and each subwidget in your `messages*.properties` files.\nFor example:\n\n```\nlabel.diffBlock.custom=My custom diff block title\nlabel.customSchema.customField=Custom field\nlabel.customSchema.customField.firstComplexItem=First item of the complex custom field\n```\n\n### Content diff\n\nWork in progress!\n\n# About Nuxeo\n\nNuxeo dramatically improves how content-based applications are built, managed and deployed, making customers more agile, innovative and successful. Nuxeo provides a next generation, enterprise ready platform for building traditional and cutting-edge content oriented applications. Combining a powerful application development environment with SaaS-based tools and a modular architecture, the Nuxeo Platform and Products provide clear business value to some of the most recognizable brands including Verizon, Electronic Arts, Sharp, FICO, the U.S. Navy, and Boeing. Nuxeo is headquartered in New York and Paris. More information is available at www.nuxeo.com.\n",
            "digest": "56f1f6c0b7c5c1f67502f8718bf655e4",
            "encoding": "UTF-8",
            "length": 16731,
            "mimeType": "text/plain",
            "name": "README.md"
          }
        ],
        "version": "2023.25"
      },
      "bundleId": "org.nuxeo.diff.content",
      "components": [
        {
          "@type": "NXComponent",
          "documentation": "\n    Adapters for content diff\n  \n",
          "documentationHtml": "<p>\nAdapters for content diff\n</p><p></p>",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.core.api.DocumentAdapterService--adapters",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapters/Contributions/org.nuxeo.ecm.diff.content.adapters--adapters",
              "id": "org.nuxeo.ecm.diff.content.adapters--adapters",
              "registrationOrder": 5,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.core.api.DocumentAdapterService",
                "name": "org.nuxeo.ecm.core.api.DocumentAdapterService",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"adapters\" target=\"org.nuxeo.ecm.core.api.DocumentAdapterService\">\n    <adapter class=\"org.nuxeo.ecm.diff.content.ContentDiffAdapter\" factory=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffDocumentModelAdapterFactory\"/>\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapters",
          "name": "org.nuxeo.ecm.diff.content.adapters",
          "requirements": [],
          "resolutionOrder": 174,
          "services": [],
          "startOrder": 191,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.content.adapters\">\n  <documentation>\n    Adapters for content diff\n  </documentation>\n\n  <extension target=\"org.nuxeo.ecm.core.api.DocumentAdapterService\"\n    point=\"adapters\">\n    <adapter class=\"org.nuxeo.ecm.diff.content.ContentDiffAdapter\"\n      factory=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffDocumentModelAdapterFactory\" />\n  </extension>\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-document-adapter-contrib.xml",
          "xmlPureComponent": true
        },
        {
          "@type": "NXComponent",
          "componentClass": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
          "documentation": "\n    @author Antoine Taillefer (ataillefer@nuxeo.com)\n  \n",
          "documentationHtml": "<p></p>",
          "extensionPoints": [
            {
              "@type": "NXExtensionPoint",
              "componentId": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
              "descriptors": [
                "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterFactoryDescriptor"
              ],
              "documentation": "\n      @author Antoine Taillefer (ataillefer@nuxeo.com)\n    \n",
              "documentationHtml": "<p></p>",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent/ExtensionPoints/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--adapterFactory",
              "id": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--adapterFactory",
              "label": "adapterFactory (org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent)",
              "name": "adapterFactory",
              "version": "2023.25.10"
            },
            {
              "@type": "NXExtensionPoint",
              "componentId": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
              "descriptors": [
                "org.nuxeo.ecm.diff.content.adapter.MimeTypeContentDifferDescriptor"
              ],
              "documentation": "\n      Allows to contribute default implementation of\n      content diff according to the mime type.\n    \n",
              "documentationHtml": "<p>\nAllows to contribute default implementation of\ncontent diff according to the mime type.\n</p><p></p>",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent/ExtensionPoints/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--mimeTypeContentDiffer",
              "id": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--mimeTypeContentDiffer",
              "label": "mimeTypeContentDiffer (org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent)",
              "name": "mimeTypeContentDiffer",
              "version": "2023.25.10"
            },
            {
              "@type": "NXExtensionPoint",
              "componentId": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
              "descriptors": [
                "org.nuxeo.ecm.diff.content.MimeTypesDescriptor"
              ],
              "documentation": "\n      @since 10.10\n\n      Allows to contribute the list of blacklisted mime types for HTML\n      conversion.\n\n      By default, contributing a list merges its mime types\n      with the existing ones.\n      To remove a mime type, use enabled=false.\n      <code>\n    <extension point=\"htmlConversionBlacklistedMimeTypes\" target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n        <mimeTypes>\n            <mimeType>application/msword</mimeType>\n            <mimeType>application/rtf</mimeType>\n            <mimeType enabled=\"false\">application/pdf</mimeType>\n        </mimeTypes>\n    </extension>\n</code>\n\n\n      To override the whole list, use override=\"true\".\n      <code>\n    <extension point=\"htmlConversionBlacklistedMimeTypes\" target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n        <mimeTypes override=\"true\">\n            <mimeType>application/msword</mimeType>\n        </mimeTypes>\n    </extension>\n</code>\n",
              "documentationHtml": "<p>\n&#64;since 10.10\n</p><p>\nAllows to contribute the list of blacklisted mime types for HTML\nconversion.\n</p><p>\nBy default, contributing a list merges its mime types\nwith the existing ones.\nTo remove a mime type, use enabled&#61;false.\n</p><p></p><pre><code>    &lt;extension point&#61;&#34;htmlConversionBlacklistedMimeTypes&#34; target&#61;&#34;org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent&#34;&gt;\n        &lt;mimeTypes&gt;\n            &lt;mimeType&gt;application/msword&lt;/mimeType&gt;\n            &lt;mimeType&gt;application/rtf&lt;/mimeType&gt;\n            &lt;mimeType enabled&#61;&#34;false&#34;&gt;application/pdf&lt;/mimeType&gt;\n        &lt;/mimeTypes&gt;\n    &lt;/extension&gt;\n</code></pre><p>\nTo override the whole list, use override&#61;&#34;true&#34;.\n</p><p></p><pre><code>    &lt;extension point&#61;&#34;htmlConversionBlacklistedMimeTypes&#34; target&#61;&#34;org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent&#34;&gt;\n        &lt;mimeTypes override&#61;&#34;true&#34;&gt;\n            &lt;mimeType&gt;application/msword&lt;/mimeType&gt;\n        &lt;/mimeTypes&gt;\n    &lt;/extension&gt;\n</code></pre><p></p>",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent/ExtensionPoints/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--htmlConversionBlacklistedMimeTypes",
              "id": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--htmlConversionBlacklistedMimeTypes",
              "label": "htmlConversionBlacklistedMimeTypes (org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent)",
              "name": "htmlConversionBlacklistedMimeTypes",
              "version": "2023.25.10"
            }
          ],
          "extensions": [],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
          "name": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
          "requirements": [],
          "resolutionOrder": 175,
          "services": [
            {
              "@type": "NXService",
              "componentId": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent/Services/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManager",
              "id": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManager",
              "overriden": false,
              "version": "2023.25.10"
            }
          ],
          "startOrder": 830,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component\n  name=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n  <implementation\n    class=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\" />\n\n  <documentation>\n    @author Antoine Taillefer (ataillefer@nuxeo.com)\n  </documentation>\n\n  <service>\n    <provide\n      interface=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManager\" />\n  </service>\n\n  <extension-point name=\"adapterFactory\">\n    <documentation>\n      @author Antoine Taillefer (ataillefer@nuxeo.com)\n    </documentation>\n    <object\n      class=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterFactoryDescriptor\" />\n  </extension-point>\n\n  <extension-point name=\"mimeTypeContentDiffer\">\n    <documentation>\n      Allows to contribute default implementation of\n      content diff according to the mime type.\n    </documentation>\n    <object\n      class=\"org.nuxeo.ecm.diff.content.adapter.MimeTypeContentDifferDescriptor\" />\n  </extension-point>\n\n  <extension-point\n    name=\"htmlConversionBlacklistedMimeTypes\">\n    <documentation>\n      @since 10.10\n\n      Allows to contribute the list of blacklisted mime types for HTML\n      conversion.\n\n      By default, contributing a list merges its mime types\n      with the existing ones.\n      To remove a mime type, use enabled=false.\n      <code>\n        <extension\n          target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\"\n          point=\"htmlConversionBlacklistedMimeTypes\">\n          <mimeTypes>\n            <mimeType>application/msword</mimeType>\n            <mimeType>application/rtf</mimeType>\n            <mimeType enabled=\"false\">application/pdf</mimeType>\n          </mimeTypes>\n        </extension>\n      </code>\n\n      To override the whole list, use override=\"true\".\n      <code>\n        <extension\n          target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\"\n          point=\"htmlConversionBlacklistedMimeTypes\">\n          <mimeTypes override=\"true\">\n            <mimeType>application/msword</mimeType>\n          </mimeTypes>\n        </extension>\n      </code>\n    </documentation>\n    <object\n      class=\"org.nuxeo.ecm.diff.content.MimeTypesDescriptor\" />\n  </extension-point>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-adapter-framework.xml",
          "xmlPureComponent": false
        },
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentation": "\n      Default builtin content diff adapters\n    \n",
              "documentationHtml": "<p>\nDefault builtin content diff adapters\n</p><p></p>",
              "extensionPoint": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--adapterFactory",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.contrib/Contributions/org.nuxeo.ecm.diff.content.adapter.contrib--adapterFactory",
              "id": "org.nuxeo.ecm.diff.content.adapter.contrib--adapterFactory",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "name": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"adapterFactory\" target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n\n    <documentation>\n      Default builtin content diff adapters\n    </documentation>\n\n  </extension>"
            },
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--mimeTypeContentDiffer",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.contrib/Contributions/org.nuxeo.ecm.diff.content.adapter.contrib--mimeTypeContentDiffer",
              "id": "org.nuxeo.ecm.diff.content.adapter.contrib--mimeTypeContentDiffer",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "name": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"mimeTypeContentDiffer\" target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n    <contentDiffer class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/html</pattern>\n    </contentDiffer>\n    <contentDiffer class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/plain</pattern>\n    </contentDiffer>\n    <contentDiffer class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/xml</pattern>\n    </contentDiffer>\n    <contentDiffer class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>application/json</pattern>\n    </contentDiffer>\n  </extension>"
            },
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--htmlConversionBlacklistedMimeTypes",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.contrib/Contributions/org.nuxeo.ecm.diff.content.adapter.contrib--htmlConversionBlacklistedMimeTypes",
              "id": "org.nuxeo.ecm.diff.content.adapter.contrib--htmlConversionBlacklistedMimeTypes",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "name": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"htmlConversionBlacklistedMimeTypes\" target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n    <mimeTypes>\n      <!-- PDF -->\n      <mimeType>application/pdf</mimeType>\n\n      <!-- Office spreadsheet -->\n      <mimeType>application/vnd.ms-excel</mimeType>\n      <mimeType>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\n      </mimeType>\n      <mimeType>application/vnd.sun.xml.calc</mimeType>\n      <mimeType>application/vnd.sun.xml.calc.template</mimeType>\n      <mimeType>application/vnd.oasis.opendocument.spreadsheet\n      </mimeType>\n      <mimeType>application/vnd.oasis.opendocument.spreadsheet-template\n      </mimeType>\n\n      <!-- Office presentation -->\n      <mimeType>application/vnd.ms-powerpoint</mimeType>\n      <mimeType>application/vnd.openxmlformats-officedocument.presentationml.presentation\n      </mimeType>\n      <mimeType>application/vnd.sun.xml.impress</mimeType>\n      <mimeType>application/vnd.sun.xml.impress.template</mimeType>\n      <mimeType>application/vnd.oasis.opendocument.presentation\n      </mimeType>\n      <mimeType>application/vnd.oasis.opendocument.presentation-template\n      </mimeType>\n    </mimeTypes>\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.contrib",
          "name": "org.nuxeo.ecm.diff.content.adapter.contrib",
          "requirements": [],
          "resolutionOrder": 176,
          "services": [],
          "startOrder": 190,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.content.adapter.contrib\">\n  <extension\n    target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\"\n    point=\"adapterFactory\">\n\n    <documentation>\n      Default builtin content diff adapters\n    </documentation>\n\n  </extension>\n\n  <extension\n    target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\"\n    point=\"mimeTypeContentDiffer\">\n    <contentDiffer\n      class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/html</pattern>\n    </contentDiffer>\n    <contentDiffer\n      class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/plain</pattern>\n    </contentDiffer>\n    <contentDiffer\n      class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/xml</pattern>\n    </contentDiffer>\n    <contentDiffer\n      class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>application/json</pattern>\n    </contentDiffer>\n  </extension>\n\n  <extension\n    target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\"\n    point=\"htmlConversionBlacklistedMimeTypes\">\n    <mimeTypes>\n      <!-- PDF -->\n      <mimeType>application/pdf</mimeType>\n\n      <!-- Office spreadsheet -->\n      <mimeType>application/vnd.ms-excel</mimeType>\n      <mimeType>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\n      </mimeType>\n      <mimeType>application/vnd.sun.xml.calc</mimeType>\n      <mimeType>application/vnd.sun.xml.calc.template</mimeType>\n      <mimeType>application/vnd.oasis.opendocument.spreadsheet\n      </mimeType>\n      <mimeType>application/vnd.oasis.opendocument.spreadsheet-template\n      </mimeType>\n\n      <!-- Office presentation -->\n      <mimeType>application/vnd.ms-powerpoint</mimeType>\n      <mimeType>application/vnd.openxmlformats-officedocument.presentationml.presentation\n      </mimeType>\n      <mimeType>application/vnd.sun.xml.impress</mimeType>\n      <mimeType>application/vnd.sun.xml.impress.template</mimeType>\n      <mimeType>application/vnd.oasis.opendocument.presentation\n      </mimeType>\n      <mimeType>application/vnd.oasis.opendocument.presentation-template\n      </mimeType>\n    </mimeTypes>\n  </extension>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-adapter-contrib.xml",
          "xmlPureComponent": true
        },
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentation": "\n      Allows to limit the diff count between two files.\n      @since 2021.24\n    \n",
              "documentationHtml": "<p>\nAllows to limit the diff count between two files.\n&#64;since 2021.24\n</p><p></p>",
              "extensionPoint": "org.nuxeo.runtime.ConfigurationService--configuration",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.settings/Contributions/org.nuxeo.ecm.diff.settings--configuration",
              "id": "org.nuxeo.ecm.diff.settings--configuration",
              "registrationOrder": 25,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.runtime.ConfigurationService",
                "name": "org.nuxeo.runtime.ConfigurationService",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"configuration\" target=\"org.nuxeo.runtime.ConfigurationService\">\n    <documentation>\n      Allows to limit the diff count between two files.\n      @since 2021.24\n    </documentation>\n    <property name=\"nuxeo.diff.limit\">100000</property>\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.settings",
          "name": "org.nuxeo.ecm.diff.settings",
          "requirements": [],
          "resolutionOrder": 177,
          "services": [],
          "startOrder": 196,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.settings\">\n  <extension target=\"org.nuxeo.runtime.ConfigurationService\" point=\"configuration\">\n    <documentation>\n      Allows to limit the diff count between two files.\n      @since 2021.24\n    </documentation>\n    <property name=\"nuxeo.diff.limit\">${nuxeo.diff.limit:=100000}</property>\n  </extension>\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-config.xml",
          "xmlPureComponent": true
        },
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.core.convert.service.ConversionServiceImpl--converter",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.converter.contrib/Contributions/org.nuxeo.ecm.diff.content.converter.contrib--converter",
              "id": "org.nuxeo.ecm.diff.content.converter.contrib--converter",
              "registrationOrder": 5,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.core.convert.service.ConversionServiceImpl",
                "name": "org.nuxeo.ecm.core.convert.service.ConversionServiceImpl",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"converter\" target=\"org.nuxeo.ecm.core.convert.service.ConversionServiceImpl\">\n\n    <converter class=\"org.nuxeo.ecm.diff.content.converters.ContentDiffHtmlConverter\" name=\"contentDiffHtmlConverter\">\n      <sourceMimeType>*</sourceMimeType>\n      <destinationMimeType>text/html</destinationMimeType>\n    </converter>\n\n    <converter class=\"org.nuxeo.ecm.diff.content.converters.ContentDiffTextConverter\" name=\"contentDiffTextConverter\">\n      <sourceMimeType>*</sourceMimeType>\n      <destinationMimeType>text/plain</destinationMimeType>\n    </converter>\n\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.converter.contrib",
          "name": "org.nuxeo.ecm.diff.content.converter.contrib",
          "requirements": [
            "org.nuxeo.ecm.core.convert.plugins",
            "org.nuxeo.ecm.platform.convert.plugins"
          ],
          "resolutionOrder": 343,
          "services": [],
          "startOrder": 192,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.content.converter.contrib\">\n\n  <require>org.nuxeo.ecm.platform.convert.plugins</require>\n  <require>org.nuxeo.ecm.core.convert.plugins</require>\n\n  <extension target=\"org.nuxeo.ecm.core.convert.service.ConversionServiceImpl\"\n    point=\"converter\">\n\n    <converter name=\"contentDiffHtmlConverter\" class=\"org.nuxeo.ecm.diff.content.converters.ContentDiffHtmlConverter\">\n      <sourceMimeType>*</sourceMimeType>\n      <destinationMimeType>text/html</destinationMimeType>\n    </converter>\n\n    <converter name=\"contentDiffTextConverter\" class=\"org.nuxeo.ecm.diff.content.converters.ContentDiffTextConverter\">\n      <sourceMimeType>*</sourceMimeType>\n      <destinationMimeType>text/plain</destinationMimeType>\n    </converter>\n\n  </extension>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-convert-service-contrib.xml",
          "xmlPureComponent": true
        }
      ],
      "fileName": "nuxeo-diff-content-2023.25.10.jar",
      "groupId": "org.nuxeo.ecm",
      "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content",
      "id": "org.nuxeo.diff.content",
      "location": "",
      "manifest": "Manifest-Version: 1.0\r\nArchiver-Version: Plexus Archiver\r\nCreated-By: Apache Maven 3.9.6\r\nBuilt-By: root\r\nBuild-Jdk: 17.0.14\r\nBundle-ManifestVersion: 2\r\nBundle-Version: 5.6\r\nBundle-ActivationPolicy: lazy\r\nBundle-ClassPath: .\r\nBundle-Name: org.nuxeo.diff\r\nBundle-RequiredExecutionEnvironment: JavaSE-1.6\r\nBundle-Vendor: Nuxeo\r\nBundle-SymbolicName: org.nuxeo.diff.content;singleton:=true\r\nNuxeo-Component: OSGI-INF/content-diff-document-adapter-contrib.xml,OSGI\r\n -INF/content-diff-adapter-framework.xml,OSGI-INF/content-diff-adapter-c\r\n ontrib.xml,OSGI-INF/content-diff-convert-service-contrib.xml,OSGI-INF/c\r\n ontent-diff-config.xml\r\n\r\n",
      "maxResolutionOrder": 343,
      "minResolutionOrder": 174,
      "packages": [
        "nuxeo-diff"
      ],
      "parentReadme": {
        "blobProviderId": "default",
        "content": "# Nuxeo Diff\n\nThis repo hosts the source code of a plugin for Nuxeo Platform that allows to render a diff between two documents or two versions of a document.\nThe comparison takes into account all the properties shared by the documents, which means that if a comparison is done between two documents of a different type, only the schemas in common will be \"diffed\".\nThe comparison also takes into account blob-type properties.\n\n\n## Building and deploying\n\n    mvn clean install\n\n## Deploying\n\nInstall [the Nuxeo Diff Marketplace Package](https://connect.nuxeo.com/nuxeo/site/marketplace/package/nuxeo-diff).\n\n## Configuring\n\n### Diff display\n\nThe `DiffDisplayService` offers several extension points to configure the document diff display.\nMost of the code samples exposed here can be found in the [diff-display-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-display-contrib.xml) and [diff-widgets-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-widgets-contrib.xml) files.\n\n#### Configuring groups of properties to display with the diffDisplay extension point.\n\nA `diffDisplay` contribution represents a number of `diffBlocks` that you want to display when asking for a document comparison.\nIt is bound to a document type.\nA `diffBlock` contribution represents a number of properties (fields) that you want to display (see next section).\n\nWhen asking for the comparison between 2 versions of a document, the `diffDisplay` bound to the document type or a super type is used.\nIf no `diffDisplay` is found for this type or a super type a fall back is done on the default diff display mode: one block per document schema and for each block all the fields of the schema that are different.\n\n*Beware that in this case the order of the schemas and of the fields is undefined.*\n\nWhen asking for the comparison between 2 documents:\n- If they are of the same type: if  a `diffDisplay` is found for this type or a super type then it is used, else a fall back is done on the default diff display mode.\n- If they are of different types: if  a `diffDisplay` is found for a common super type then it is used, else a fall back is done on the default diff display mode.\n\nFor example, this is the `diffDisplay` contribution bound to the _File_ type:\n```xml\n<diffDisplay type=\"File\">\n  <diffBlocks>\n    <diffBlock name=\"heading\" />\n    <diffBlock name=\"dublincore\" />\n    <diffBlock name=\"files\" />\n  </diffDisplay>\n</diffBlocks>\n```\n\n_Note that the order of the diffBlocks is taken into account when rendering the diff display._\n\n#### Configuring a group of properties to display with the diffBlock extension point\n\nA `diffBlock` contribution represents a number of `fields` that you want to display. It is rendered as a foldable box.\nThe `label` attribute of a `diffBlock` contribution is used as the title of the foldable box.\nA `field` is defined by its `schema` and its `name`.\n\nFor example, this is the \"heading\" `diffBlock` contribution:\n```xml\n<diffBlock name=\"heading\" label=\"label.diffBlock.heading\">\n  <fields>\n    <field schema=\"dublincore\" name=\"title\" />\n    <field schema=\"dublincore\" name=\"description\" />\n  </fields>\n</diffBlock>\n```\n_Note that the order of the fields is taken into account when rendering the diff block._\n\nFor complex properties, you can contribute inside the `field` element the property `items` that you want to display:\n```xml\n<field schema=\"complextypes\" name=\"complex\">\n  <items>\n    <item name=\"stringItem\" />\n    <item name=\"thirdItem\" />\n    <item name=\"fourthItem\" />\n  </items>\n</field>\n```\n\n_Note that the order of the items is taken into account when rendering the field._\n\nThis is used for the `files` field of the `files` diff block:\n```xml\n<field schema=\"files\" name=\"files\">\n  <items>\n    <!-- Display the file only, not the filename which is managed\n         by the file widget type -->\n    <item name=\"file\" displayContentDiffLinks=\"true\" />\n  </items>\n</field>\n```\n\nIf no `items` are specified, all the property items are displayed.\n\nFor content properties (that hold a blob) or string ones you can set the `displayContentDiffLinks` attribute to `true` on a `field` or an `item` to display the content diff links.\nThese links will open a fancybox showing the detailed content diff using the usual green and red colors to distinguish the added/removed parts of the content.\nFor now, 2 links are displayed: _Textual diff_ based on a text conversion and _Html diff_ based on an html conversion (keeps the content layout).\n\n#### Configuring property widgets with the widgets extension point\n\n##### Principle\n\nWhen rendering a `diffBlock`, the `DiffDisplayService` builds a layout definition on the fly, including a layout row for each `field` of the `diffBlock`.\nEach row contains a widget definition for the `field`, and the layout template renders 2 instances of this widget definition: one for the left document and one for the right document.\nThe content diff links, if displayed, are also rendered by a widget inside the layout row.\n\nHow is the widget definition built for a given `field`?\nA lookup is done in the `LayoutStore` service to find a specific widget definition named with the xpath of the property.\nIf such a definition is not found, a lookup is done to find a generic widget definition named with the type of the property.\n\nThis allows you to only contribute a specific widget definition if the generic one doesn't match your needs for a given field, typically if you need a custom template, label or custom properties.\n\n##### Example\n\nLets say we have contributed the following `diffBlock`:\n```xml\n<diffBlock name=\"myCustomBlock\" label=\"label.diffBlock.custom\">\n  <fields>\n    <field schema=\"file\" name=\"content\" />\n    <field schema=\"dublincore\" name=\"title\" />\n  </fields>\n</diffBlock>\n```\n\nand the following widgets to the `widgets` extension point of the `org.nuxeo.ecm.platform.forms.layout.LayoutStore` component:\n```xml\n<extension target=\"org.nuxeo.ecm.platform.forms.layout.LayoutStore\"\n  point=\"widgets\">\n\n  <widget name=\"file:content\" type=\"file\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <labels>\n      <label mode=\"any\">label.summary.download.file</label>\n    </labels>\n    <translated>true</translated>\n    <properties mode=\"any\">\n    </properties>\n  </widget>\n\n  <widget name=\"string\" type=\"template\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <properties mode=\"any\">\n      <property name=\"widgetType\">text</property>\n      <property name=\"template\">\n        /widgets/generic_diff_widget_template.xhtml\n      </property>\n    </properties>\n  </widget>\n\n</extension>\n```\n\nWhen rendering the \"myCustomBlock\" `diffBlock`, the `DiffDisplayService` will:\n\n- Look for a specific widget definition named \"file:content\" in the `LayoutStore`, find it and use it for the \"file:content\" field.\n\n- Look for a specific widget definition named \"dublincore:title\" in the `LayoutStore`, won't find it and therefore will look for a generic widget definition named with the field type, ie. \"string\", find it and use it for the dublincore:title field.\n\nIn this use case, the \"string\" generic widget definition is sufficient to display the \"dublincore:title\" field.\nIt uses a widget of type \"text\" with \"label.dublincore.title\" as a label and \"dublincore:title\" as a field definition.\nWe can easily understand here the interest of generic widgets: once you have the type and xpath of a property, the matching widget definition can be computed on the fly using the property type to guess the widget type (\"string\" => \"text\", \"date\" => \"datetime\", etc.) and the property xpath for the field definition and label.\n\nThe \"file:content\" specific widget definition is contributed here to use a custom label \"label.summary.download.file\" instead of the one that would have been generated for the \"content\" generic widget definition: \"label.file.content\".\n\n_Note that in both cases (generic and specific) you don't need to define the widget field definitions since they are automatically computed from the property xpath, except in particular cases like \"note:note\" where the \"mime-type\" field is needed._\n\n##### List and complex properties\n\nYou might already know that the widgets used to display list and complex properties have subwidgets.\nIn the case of a list property, a subwidget is needed for the list items; in the case of a complex property, a subwidget is needed for each item of the complex property.\nThe lookup done by the `DiffDisplayService_` for the first-level widgets is also done recursively for the subwidgets!\n\n###### List property\n\nFor a list property, lets take the example of \"dublincore:contributors\", which is a string list.\n\n- To display the list, nothing special is needed so the \"scalarList\" generic widget definition can be used.\n\n- To display a list item (a contributor, which is of type \"string\"), the \"string\" generic widget definition doesn't match our needs: it would display the contributor's username whereas we want to display its fullname (firstname lastname).\nSo we need a specific widget definition for the list items subwidget to use a custom template able to display the contributor's fullname.\nThe name of this widget definition must match the xpath of the list item property, ie. \"dublincore:contributors/item\".\n\nTherefore, two widget definitions are involved:\n\n- The \"scalarList\" generic widget definition:\n\n```xml\n<widget name=\"scalarList\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"displayAllItems\">false</property>\n    <property name=\"displayItemIndexes\">true</property>\n    <property name=\"template\">\n      /widgets/list_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"dublincore:contributors/item\" specific widget definition:\n\n```xml\n<widget name=\"dublincore:contributors/item\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.dublincore.contributors.item</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"template\">/widgets/contributors_item_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n###### Complex property\n\nFor a complex property, lets take the example of a \"complextypes:complex\" property with two items \"stringItem\" and \"directoryItem\".\n\"stringItem\" is a simple string, but \"directoryItem\" is a string that needs to be bound to the \"myDirectory\" directory.\n\n- To display the complex property, nothing special is needed so the \"complex\" generic widget definition can be used.\n\n- To display the \"directoryItem\" item, the \"string\" generic widget definition doesn't match our needs: it would display the directory entry code stored in the backend whereas we want to display its label.\nSo we need a specific widget definition for the \"directoryItem\" subwidget to use the \"selectOneDirectory\" widget type bound to the \"myDirectory\" directory.\nAs for a list item, the name of this widget definition must match the xpath of the complex property item, ie. \"complextypes:complex/directoryItem\".\n\nTherefore, two widget definitions are involved:\n\n- The \"complex\" generic widget definition:\n\n```xml\n<widget name=\"complex\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"template\">\n      /widgets/complex_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"complextypes:complex/directoryItem\" specific widget definition:\n\n```xml\n<widget name=\"complextypes:complex/directoryItem\" type=\"selectOneDirectory\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.complextypes.complex.directoryItem</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"directoryName\">myDirectory</property>\n    <property name=\"localize\">true</property>\n    <property name=\"ordering\">ordering,label</property>\n  </properties>\n</widget>\n```\n\n###### Useful widget properties\n\nYou can use the following properties on a list widget definition (typically \"scalarList\", \"complexList\" or \"files:files\"):\n\n`<property name=\"displayAllItems\">[true|false]</property>`\nIf set to `true`, all the list items will be displayed, otherwise only the different ones will be.\n\n`<property name=\"displayItemIndexes\">[true|false]</property>`\nIf set to `true`, a subwidget will be added to the widget definition to display the list item indexes.\n\nYou can use the following property on a complex widget definition (typically \"complex\"):\n\n`<property name=\"display\">[inline|*]</property>`\nIf set to `inline` the complex items will be displayed as a table with one line and one column per item, otherwise as a table with one column and one line per item.\n\n##### About the value bound to the diff widgets\n\nIf you take a look at [layout_diff_template.xhtml](nuxeo-diff-jsf/src/main/resources/web/nuxeo.war/layouts/layout_diff_template.xhtml), you will see that the `value` passed to the `<nxl:widget>` tag is `#{value.leftValue}` or `#{value.rightValue}`, `value` being the object passed to the `<nxl:layout>` tag `value` attribute: `diffDisplayBlock`, of type `DiffDisplayBlockImpl`.\nThe `leftValue` and `rightValue` members of `DiffDisplayBlockImpl` are of type `Map<String, Map<String, PropertyDiffDisplay>>`. The first level Map keys are schema names, the second level ones are field keys.\nFinally, the `PropertyDiffDisplay` object has two members: `value` and `styleClass`, `value` holding the value to display and `styleClass` the css style class to apply to the &lt;span&gt; wrapping the value.\n\nFor example if we compare two documents where only the \"dublincore:title\" property is different (\"My first doc\" and \"My second doc\") we could have the following `diffDisplayBlock` object:\n\n```java\ndiffDisplayBlock.getLeftValue() = {dublincore={title={value=\"My first doc\", styleClass=\"redBackgroundColor\"}}}\ndiffDisplayBlock.getRightValue() = {dublincore={title={value=\"My second doc\", styleClass=\"greenBackgroundColor\"}}}\n```\n\nOn the widget side, the field definitions must match the `diffDisplayBlock` object structure, that's why the generated field definitions of the widget used for \"dublincore:title\" would be:\n\n```xml\n<fields>\n  <field>dublincore:title/value</field>\n  <field>dublincore:title/styleClass</field>\n</fields>\n```\n\nThis is important to know when designing a custom template for a diff widget (ie. where field definitions are automatically generated): you can use `#{field_0}` for the value itself and `#{field_1`} for the css style class associated to the value.\nBy default, only the items of a complex property or of a list property where the `displayAllItems` widget property is `true` can have a styleClass equal to `redBackgroundColor` or `greenBackgroundColor` in order to highlight the different items among all.\n\n#### To summarize: what you need to contribute to have a nice diff result for your custom document types\n\n- A `diffDisplay` contribution for each document type.\n\n- The associated `diffBlock` contributions. Don't forget that you can specify the items you want to display for a complex property and the fields/items for which you want to display the content diff links.\n\n- The specific widgets needed when the generic ones don't match your needs. Typically for a date property if you need to change the date format, or for a property bound to a directory to specifiy the directory name. Also don't forget that you can contribute a specific widget for a complex property item or a list item, using the item xpath.\n\n- The labels for each `diffBlock`, each widget and each subwidget in your `messages*.properties` files.\nFor example:\n\n```\nlabel.diffBlock.custom=My custom diff block title\nlabel.customSchema.customField=Custom field\nlabel.customSchema.customField.firstComplexItem=First item of the complex custom field\n```\n\n### Content diff\n\nWork in progress!\n\n# About Nuxeo\n\nNuxeo dramatically improves how content-based applications are built, managed and deployed, making customers more agile, innovative and successful. Nuxeo provides a next generation, enterprise ready platform for building traditional and cutting-edge content oriented applications. Combining a powerful application development environment with SaaS-based tools and a modular architecture, the Nuxeo Platform and Products provide clear business value to some of the most recognizable brands including Verizon, Electronic Arts, Sharp, FICO, the U.S. Navy, and Boeing. Nuxeo is headquartered in New York and Paris. More information is available at www.nuxeo.com.\n",
        "digest": "56f1f6c0b7c5c1f67502f8718bf655e4",
        "encoding": "UTF-8",
        "length": 16731,
        "mimeType": "text/plain",
        "name": "README.md"
      },
      "requirements": [],
      "version": "2023.25.10"
    },
    {
      "@type": "NXBundle",
      "artifactId": "nuxeo-diff-core",
      "artifactVersion": "2023.25.10",
      "bundleGroup": {
        "@type": "NXBundleGroup",
        "bundleIds": [
          "org.nuxeo.diff.content",
          "org.nuxeo.diff.core",
          "org.nuxeo.diff.jsf"
        ],
        "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff",
        "id": "grp:org.nuxeo.diff",
        "name": "org.nuxeo.diff",
        "parentIds": [
          "grp:org.nuxeo.ecm"
        ],
        "readmes": [
          {
            "blobProviderId": "default",
            "content": "# Nuxeo Diff\n\nThis repo hosts the source code of a plugin for Nuxeo Platform that allows to render a diff between two documents or two versions of a document.\nThe comparison takes into account all the properties shared by the documents, which means that if a comparison is done between two documents of a different type, only the schemas in common will be \"diffed\".\nThe comparison also takes into account blob-type properties.\n\n\n## Building and deploying\n\n    mvn clean install\n\n## Deploying\n\nInstall [the Nuxeo Diff Marketplace Package](https://connect.nuxeo.com/nuxeo/site/marketplace/package/nuxeo-diff).\n\n## Configuring\n\n### Diff display\n\nThe `DiffDisplayService` offers several extension points to configure the document diff display.\nMost of the code samples exposed here can be found in the [diff-display-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-display-contrib.xml) and [diff-widgets-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-widgets-contrib.xml) files.\n\n#### Configuring groups of properties to display with the diffDisplay extension point.\n\nA `diffDisplay` contribution represents a number of `diffBlocks` that you want to display when asking for a document comparison.\nIt is bound to a document type.\nA `diffBlock` contribution represents a number of properties (fields) that you want to display (see next section).\n\nWhen asking for the comparison between 2 versions of a document, the `diffDisplay` bound to the document type or a super type is used.\nIf no `diffDisplay` is found for this type or a super type a fall back is done on the default diff display mode: one block per document schema and for each block all the fields of the schema that are different.\n\n*Beware that in this case the order of the schemas and of the fields is undefined.*\n\nWhen asking for the comparison between 2 documents:\n- If they are of the same type: if  a `diffDisplay` is found for this type or a super type then it is used, else a fall back is done on the default diff display mode.\n- If they are of different types: if  a `diffDisplay` is found for a common super type then it is used, else a fall back is done on the default diff display mode.\n\nFor example, this is the `diffDisplay` contribution bound to the _File_ type:\n```xml\n<diffDisplay type=\"File\">\n  <diffBlocks>\n    <diffBlock name=\"heading\" />\n    <diffBlock name=\"dublincore\" />\n    <diffBlock name=\"files\" />\n  </diffDisplay>\n</diffBlocks>\n```\n\n_Note that the order of the diffBlocks is taken into account when rendering the diff display._\n\n#### Configuring a group of properties to display with the diffBlock extension point\n\nA `diffBlock` contribution represents a number of `fields` that you want to display. It is rendered as a foldable box.\nThe `label` attribute of a `diffBlock` contribution is used as the title of the foldable box.\nA `field` is defined by its `schema` and its `name`.\n\nFor example, this is the \"heading\" `diffBlock` contribution:\n```xml\n<diffBlock name=\"heading\" label=\"label.diffBlock.heading\">\n  <fields>\n    <field schema=\"dublincore\" name=\"title\" />\n    <field schema=\"dublincore\" name=\"description\" />\n  </fields>\n</diffBlock>\n```\n_Note that the order of the fields is taken into account when rendering the diff block._\n\nFor complex properties, you can contribute inside the `field` element the property `items` that you want to display:\n```xml\n<field schema=\"complextypes\" name=\"complex\">\n  <items>\n    <item name=\"stringItem\" />\n    <item name=\"thirdItem\" />\n    <item name=\"fourthItem\" />\n  </items>\n</field>\n```\n\n_Note that the order of the items is taken into account when rendering the field._\n\nThis is used for the `files` field of the `files` diff block:\n```xml\n<field schema=\"files\" name=\"files\">\n  <items>\n    <!-- Display the file only, not the filename which is managed\n         by the file widget type -->\n    <item name=\"file\" displayContentDiffLinks=\"true\" />\n  </items>\n</field>\n```\n\nIf no `items` are specified, all the property items are displayed.\n\nFor content properties (that hold a blob) or string ones you can set the `displayContentDiffLinks` attribute to `true` on a `field` or an `item` to display the content diff links.\nThese links will open a fancybox showing the detailed content diff using the usual green and red colors to distinguish the added/removed parts of the content.\nFor now, 2 links are displayed: _Textual diff_ based on a text conversion and _Html diff_ based on an html conversion (keeps the content layout).\n\n#### Configuring property widgets with the widgets extension point\n\n##### Principle\n\nWhen rendering a `diffBlock`, the `DiffDisplayService` builds a layout definition on the fly, including a layout row for each `field` of the `diffBlock`.\nEach row contains a widget definition for the `field`, and the layout template renders 2 instances of this widget definition: one for the left document and one for the right document.\nThe content diff links, if displayed, are also rendered by a widget inside the layout row.\n\nHow is the widget definition built for a given `field`?\nA lookup is done in the `LayoutStore` service to find a specific widget definition named with the xpath of the property.\nIf such a definition is not found, a lookup is done to find a generic widget definition named with the type of the property.\n\nThis allows you to only contribute a specific widget definition if the generic one doesn't match your needs for a given field, typically if you need a custom template, label or custom properties.\n\n##### Example\n\nLets say we have contributed the following `diffBlock`:\n```xml\n<diffBlock name=\"myCustomBlock\" label=\"label.diffBlock.custom\">\n  <fields>\n    <field schema=\"file\" name=\"content\" />\n    <field schema=\"dublincore\" name=\"title\" />\n  </fields>\n</diffBlock>\n```\n\nand the following widgets to the `widgets` extension point of the `org.nuxeo.ecm.platform.forms.layout.LayoutStore` component:\n```xml\n<extension target=\"org.nuxeo.ecm.platform.forms.layout.LayoutStore\"\n  point=\"widgets\">\n\n  <widget name=\"file:content\" type=\"file\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <labels>\n      <label mode=\"any\">label.summary.download.file</label>\n    </labels>\n    <translated>true</translated>\n    <properties mode=\"any\">\n    </properties>\n  </widget>\n\n  <widget name=\"string\" type=\"template\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <properties mode=\"any\">\n      <property name=\"widgetType\">text</property>\n      <property name=\"template\">\n        /widgets/generic_diff_widget_template.xhtml\n      </property>\n    </properties>\n  </widget>\n\n</extension>\n```\n\nWhen rendering the \"myCustomBlock\" `diffBlock`, the `DiffDisplayService` will:\n\n- Look for a specific widget definition named \"file:content\" in the `LayoutStore`, find it and use it for the \"file:content\" field.\n\n- Look for a specific widget definition named \"dublincore:title\" in the `LayoutStore`, won't find it and therefore will look for a generic widget definition named with the field type, ie. \"string\", find it and use it for the dublincore:title field.\n\nIn this use case, the \"string\" generic widget definition is sufficient to display the \"dublincore:title\" field.\nIt uses a widget of type \"text\" with \"label.dublincore.title\" as a label and \"dublincore:title\" as a field definition.\nWe can easily understand here the interest of generic widgets: once you have the type and xpath of a property, the matching widget definition can be computed on the fly using the property type to guess the widget type (\"string\" => \"text\", \"date\" => \"datetime\", etc.) and the property xpath for the field definition and label.\n\nThe \"file:content\" specific widget definition is contributed here to use a custom label \"label.summary.download.file\" instead of the one that would have been generated for the \"content\" generic widget definition: \"label.file.content\".\n\n_Note that in both cases (generic and specific) you don't need to define the widget field definitions since they are automatically computed from the property xpath, except in particular cases like \"note:note\" where the \"mime-type\" field is needed._\n\n##### List and complex properties\n\nYou might already know that the widgets used to display list and complex properties have subwidgets.\nIn the case of a list property, a subwidget is needed for the list items; in the case of a complex property, a subwidget is needed for each item of the complex property.\nThe lookup done by the `DiffDisplayService_` for the first-level widgets is also done recursively for the subwidgets!\n\n###### List property\n\nFor a list property, lets take the example of \"dublincore:contributors\", which is a string list.\n\n- To display the list, nothing special is needed so the \"scalarList\" generic widget definition can be used.\n\n- To display a list item (a contributor, which is of type \"string\"), the \"string\" generic widget definition doesn't match our needs: it would display the contributor's username whereas we want to display its fullname (firstname lastname).\nSo we need a specific widget definition for the list items subwidget to use a custom template able to display the contributor's fullname.\nThe name of this widget definition must match the xpath of the list item property, ie. \"dublincore:contributors/item\".\n\nTherefore, two widget definitions are involved:\n\n- The \"scalarList\" generic widget definition:\n\n```xml\n<widget name=\"scalarList\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"displayAllItems\">false</property>\n    <property name=\"displayItemIndexes\">true</property>\n    <property name=\"template\">\n      /widgets/list_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"dublincore:contributors/item\" specific widget definition:\n\n```xml\n<widget name=\"dublincore:contributors/item\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.dublincore.contributors.item</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"template\">/widgets/contributors_item_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n###### Complex property\n\nFor a complex property, lets take the example of a \"complextypes:complex\" property with two items \"stringItem\" and \"directoryItem\".\n\"stringItem\" is a simple string, but \"directoryItem\" is a string that needs to be bound to the \"myDirectory\" directory.\n\n- To display the complex property, nothing special is needed so the \"complex\" generic widget definition can be used.\n\n- To display the \"directoryItem\" item, the \"string\" generic widget definition doesn't match our needs: it would display the directory entry code stored in the backend whereas we want to display its label.\nSo we need a specific widget definition for the \"directoryItem\" subwidget to use the \"selectOneDirectory\" widget type bound to the \"myDirectory\" directory.\nAs for a list item, the name of this widget definition must match the xpath of the complex property item, ie. \"complextypes:complex/directoryItem\".\n\nTherefore, two widget definitions are involved:\n\n- The \"complex\" generic widget definition:\n\n```xml\n<widget name=\"complex\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"template\">\n      /widgets/complex_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"complextypes:complex/directoryItem\" specific widget definition:\n\n```xml\n<widget name=\"complextypes:complex/directoryItem\" type=\"selectOneDirectory\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.complextypes.complex.directoryItem</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"directoryName\">myDirectory</property>\n    <property name=\"localize\">true</property>\n    <property name=\"ordering\">ordering,label</property>\n  </properties>\n</widget>\n```\n\n###### Useful widget properties\n\nYou can use the following properties on a list widget definition (typically \"scalarList\", \"complexList\" or \"files:files\"):\n\n`<property name=\"displayAllItems\">[true|false]</property>`\nIf set to `true`, all the list items will be displayed, otherwise only the different ones will be.\n\n`<property name=\"displayItemIndexes\">[true|false]</property>`\nIf set to `true`, a subwidget will be added to the widget definition to display the list item indexes.\n\nYou can use the following property on a complex widget definition (typically \"complex\"):\n\n`<property name=\"display\">[inline|*]</property>`\nIf set to `inline` the complex items will be displayed as a table with one line and one column per item, otherwise as a table with one column and one line per item.\n\n##### About the value bound to the diff widgets\n\nIf you take a look at [layout_diff_template.xhtml](nuxeo-diff-jsf/src/main/resources/web/nuxeo.war/layouts/layout_diff_template.xhtml), you will see that the `value` passed to the `<nxl:widget>` tag is `#{value.leftValue}` or `#{value.rightValue}`, `value` being the object passed to the `<nxl:layout>` tag `value` attribute: `diffDisplayBlock`, of type `DiffDisplayBlockImpl`.\nThe `leftValue` and `rightValue` members of `DiffDisplayBlockImpl` are of type `Map<String, Map<String, PropertyDiffDisplay>>`. The first level Map keys are schema names, the second level ones are field keys.\nFinally, the `PropertyDiffDisplay` object has two members: `value` and `styleClass`, `value` holding the value to display and `styleClass` the css style class to apply to the &lt;span&gt; wrapping the value.\n\nFor example if we compare two documents where only the \"dublincore:title\" property is different (\"My first doc\" and \"My second doc\") we could have the following `diffDisplayBlock` object:\n\n```java\ndiffDisplayBlock.getLeftValue() = {dublincore={title={value=\"My first doc\", styleClass=\"redBackgroundColor\"}}}\ndiffDisplayBlock.getRightValue() = {dublincore={title={value=\"My second doc\", styleClass=\"greenBackgroundColor\"}}}\n```\n\nOn the widget side, the field definitions must match the `diffDisplayBlock` object structure, that's why the generated field definitions of the widget used for \"dublincore:title\" would be:\n\n```xml\n<fields>\n  <field>dublincore:title/value</field>\n  <field>dublincore:title/styleClass</field>\n</fields>\n```\n\nThis is important to know when designing a custom template for a diff widget (ie. where field definitions are automatically generated): you can use `#{field_0}` for the value itself and `#{field_1`} for the css style class associated to the value.\nBy default, only the items of a complex property or of a list property where the `displayAllItems` widget property is `true` can have a styleClass equal to `redBackgroundColor` or `greenBackgroundColor` in order to highlight the different items among all.\n\n#### To summarize: what you need to contribute to have a nice diff result for your custom document types\n\n- A `diffDisplay` contribution for each document type.\n\n- The associated `diffBlock` contributions. Don't forget that you can specify the items you want to display for a complex property and the fields/items for which you want to display the content diff links.\n\n- The specific widgets needed when the generic ones don't match your needs. Typically for a date property if you need to change the date format, or for a property bound to a directory to specifiy the directory name. Also don't forget that you can contribute a specific widget for a complex property item or a list item, using the item xpath.\n\n- The labels for each `diffBlock`, each widget and each subwidget in your `messages*.properties` files.\nFor example:\n\n```\nlabel.diffBlock.custom=My custom diff block title\nlabel.customSchema.customField=Custom field\nlabel.customSchema.customField.firstComplexItem=First item of the complex custom field\n```\n\n### Content diff\n\nWork in progress!\n\n# About Nuxeo\n\nNuxeo dramatically improves how content-based applications are built, managed and deployed, making customers more agile, innovative and successful. Nuxeo provides a next generation, enterprise ready platform for building traditional and cutting-edge content oriented applications. Combining a powerful application development environment with SaaS-based tools and a modular architecture, the Nuxeo Platform and Products provide clear business value to some of the most recognizable brands including Verizon, Electronic Arts, Sharp, FICO, the U.S. Navy, and Boeing. Nuxeo is headquartered in New York and Paris. More information is available at www.nuxeo.com.\n",
            "digest": "56f1f6c0b7c5c1f67502f8718bf655e4",
            "encoding": "UTF-8",
            "length": 16731,
            "mimeType": "text/plain",
            "name": "README.md"
          }
        ],
        "version": "2023.25"
      },
      "bundleId": "org.nuxeo.diff.core",
      "components": [
        {
          "@type": "NXComponent",
          "componentClass": "org.nuxeo.ecm.diff.service.impl.DocumentDiffServiceImpl",
          "documentation": "\n    This service allows to make a diff between two\n    documents, or two versions of a document.\n\n    @author\n    Antoine Taillefer\n  \n",
          "documentationHtml": "<p>\nThis service allows to make a diff between two\ndocuments, or two versions of a document.\n</p><p>\nAntoine Taillefer\n</p><p></p>",
          "extensionPoints": [],
          "extensions": [],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.core/org.nuxeo.ecm.diff.service.DocumentDiffService",
          "name": "org.nuxeo.ecm.diff.service.DocumentDiffService",
          "requirements": [],
          "resolutionOrder": 178,
          "services": [
            {
              "@type": "NXService",
              "componentId": "org.nuxeo.ecm.diff.service.DocumentDiffService",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.core/org.nuxeo.ecm.diff.service.DocumentDiffService/Services/org.nuxeo.ecm.diff.service.DocumentDiffService",
              "id": "org.nuxeo.ecm.diff.service.DocumentDiffService",
              "overriden": false,
              "version": "2023.25.10"
            }
          ],
          "startOrder": 195,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.service.DocumentDiffService\">\n\n  <documentation>\n    This service allows to make a diff between two\n    documents, or two versions of a document.\n\n    @author\n    Antoine Taillefer\n  </documentation>\n\n  <implementation\n    class=\"org.nuxeo.ecm.diff.service.impl.DocumentDiffServiceImpl\" />\n\n  <service>\n    <provide interface=\"org.nuxeo.ecm.diff.service.DocumentDiffService\" />\n  </service>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/document-diff-service.xml",
          "xmlPureComponent": false
        }
      ],
      "fileName": "nuxeo-diff-core-2023.25.10.jar",
      "groupId": "org.nuxeo.ecm",
      "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.core",
      "id": "org.nuxeo.diff.core",
      "location": "",
      "manifest": "Manifest-Version: 1.0\r\nArchiver-Version: Plexus Archiver\r\nCreated-By: Apache Maven 3.9.6\r\nBuilt-By: root\r\nBuild-Jdk: 17.0.14\r\nBundle-ManifestVersion: 2\r\nBundle-Version: 5.6\r\nBundle-ActivationPolicy: lazy\r\nBundle-ClassPath: .\r\nBundle-Name: org.nuxeo.diff.core\r\nBundle-RequiredExecutionEnvironment: JavaSE-1.6\r\nBundle-Vendor: Nuxeo\r\nBundle-SymbolicName: org.nuxeo.diff.core;singleton:=true\r\nNuxeo-Component: OSGI-INF/document-diff-service.xml\r\n\r\n",
      "maxResolutionOrder": 178,
      "minResolutionOrder": 178,
      "packages": [
        "nuxeo-diff"
      ],
      "parentReadme": {
        "blobProviderId": "default",
        "content": "# Nuxeo Diff\n\nThis repo hosts the source code of a plugin for Nuxeo Platform that allows to render a diff between two documents or two versions of a document.\nThe comparison takes into account all the properties shared by the documents, which means that if a comparison is done between two documents of a different type, only the schemas in common will be \"diffed\".\nThe comparison also takes into account blob-type properties.\n\n\n## Building and deploying\n\n    mvn clean install\n\n## Deploying\n\nInstall [the Nuxeo Diff Marketplace Package](https://connect.nuxeo.com/nuxeo/site/marketplace/package/nuxeo-diff).\n\n## Configuring\n\n### Diff display\n\nThe `DiffDisplayService` offers several extension points to configure the document diff display.\nMost of the code samples exposed here can be found in the [diff-display-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-display-contrib.xml) and [diff-widgets-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-widgets-contrib.xml) files.\n\n#### Configuring groups of properties to display with the diffDisplay extension point.\n\nA `diffDisplay` contribution represents a number of `diffBlocks` that you want to display when asking for a document comparison.\nIt is bound to a document type.\nA `diffBlock` contribution represents a number of properties (fields) that you want to display (see next section).\n\nWhen asking for the comparison between 2 versions of a document, the `diffDisplay` bound to the document type or a super type is used.\nIf no `diffDisplay` is found for this type or a super type a fall back is done on the default diff display mode: one block per document schema and for each block all the fields of the schema that are different.\n\n*Beware that in this case the order of the schemas and of the fields is undefined.*\n\nWhen asking for the comparison between 2 documents:\n- If they are of the same type: if  a `diffDisplay` is found for this type or a super type then it is used, else a fall back is done on the default diff display mode.\n- If they are of different types: if  a `diffDisplay` is found for a common super type then it is used, else a fall back is done on the default diff display mode.\n\nFor example, this is the `diffDisplay` contribution bound to the _File_ type:\n```xml\n<diffDisplay type=\"File\">\n  <diffBlocks>\n    <diffBlock name=\"heading\" />\n    <diffBlock name=\"dublincore\" />\n    <diffBlock name=\"files\" />\n  </diffDisplay>\n</diffBlocks>\n```\n\n_Note that the order of the diffBlocks is taken into account when rendering the diff display._\n\n#### Configuring a group of properties to display with the diffBlock extension point\n\nA `diffBlock` contribution represents a number of `fields` that you want to display. It is rendered as a foldable box.\nThe `label` attribute of a `diffBlock` contribution is used as the title of the foldable box.\nA `field` is defined by its `schema` and its `name`.\n\nFor example, this is the \"heading\" `diffBlock` contribution:\n```xml\n<diffBlock name=\"heading\" label=\"label.diffBlock.heading\">\n  <fields>\n    <field schema=\"dublincore\" name=\"title\" />\n    <field schema=\"dublincore\" name=\"description\" />\n  </fields>\n</diffBlock>\n```\n_Note that the order of the fields is taken into account when rendering the diff block._\n\nFor complex properties, you can contribute inside the `field` element the property `items` that you want to display:\n```xml\n<field schema=\"complextypes\" name=\"complex\">\n  <items>\n    <item name=\"stringItem\" />\n    <item name=\"thirdItem\" />\n    <item name=\"fourthItem\" />\n  </items>\n</field>\n```\n\n_Note that the order of the items is taken into account when rendering the field._\n\nThis is used for the `files` field of the `files` diff block:\n```xml\n<field schema=\"files\" name=\"files\">\n  <items>\n    <!-- Display the file only, not the filename which is managed\n         by the file widget type -->\n    <item name=\"file\" displayContentDiffLinks=\"true\" />\n  </items>\n</field>\n```\n\nIf no `items` are specified, all the property items are displayed.\n\nFor content properties (that hold a blob) or string ones you can set the `displayContentDiffLinks` attribute to `true` on a `field` or an `item` to display the content diff links.\nThese links will open a fancybox showing the detailed content diff using the usual green and red colors to distinguish the added/removed parts of the content.\nFor now, 2 links are displayed: _Textual diff_ based on a text conversion and _Html diff_ based on an html conversion (keeps the content layout).\n\n#### Configuring property widgets with the widgets extension point\n\n##### Principle\n\nWhen rendering a `diffBlock`, the `DiffDisplayService` builds a layout definition on the fly, including a layout row for each `field` of the `diffBlock`.\nEach row contains a widget definition for the `field`, and the layout template renders 2 instances of this widget definition: one for the left document and one for the right document.\nThe content diff links, if displayed, are also rendered by a widget inside the layout row.\n\nHow is the widget definition built for a given `field`?\nA lookup is done in the `LayoutStore` service to find a specific widget definition named with the xpath of the property.\nIf such a definition is not found, a lookup is done to find a generic widget definition named with the type of the property.\n\nThis allows you to only contribute a specific widget definition if the generic one doesn't match your needs for a given field, typically if you need a custom template, label or custom properties.\n\n##### Example\n\nLets say we have contributed the following `diffBlock`:\n```xml\n<diffBlock name=\"myCustomBlock\" label=\"label.diffBlock.custom\">\n  <fields>\n    <field schema=\"file\" name=\"content\" />\n    <field schema=\"dublincore\" name=\"title\" />\n  </fields>\n</diffBlock>\n```\n\nand the following widgets to the `widgets` extension point of the `org.nuxeo.ecm.platform.forms.layout.LayoutStore` component:\n```xml\n<extension target=\"org.nuxeo.ecm.platform.forms.layout.LayoutStore\"\n  point=\"widgets\">\n\n  <widget name=\"file:content\" type=\"file\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <labels>\n      <label mode=\"any\">label.summary.download.file</label>\n    </labels>\n    <translated>true</translated>\n    <properties mode=\"any\">\n    </properties>\n  </widget>\n\n  <widget name=\"string\" type=\"template\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <properties mode=\"any\">\n      <property name=\"widgetType\">text</property>\n      <property name=\"template\">\n        /widgets/generic_diff_widget_template.xhtml\n      </property>\n    </properties>\n  </widget>\n\n</extension>\n```\n\nWhen rendering the \"myCustomBlock\" `diffBlock`, the `DiffDisplayService` will:\n\n- Look for a specific widget definition named \"file:content\" in the `LayoutStore`, find it and use it for the \"file:content\" field.\n\n- Look for a specific widget definition named \"dublincore:title\" in the `LayoutStore`, won't find it and therefore will look for a generic widget definition named with the field type, ie. \"string\", find it and use it for the dublincore:title field.\n\nIn this use case, the \"string\" generic widget definition is sufficient to display the \"dublincore:title\" field.\nIt uses a widget of type \"text\" with \"label.dublincore.title\" as a label and \"dublincore:title\" as a field definition.\nWe can easily understand here the interest of generic widgets: once you have the type and xpath of a property, the matching widget definition can be computed on the fly using the property type to guess the widget type (\"string\" => \"text\", \"date\" => \"datetime\", etc.) and the property xpath for the field definition and label.\n\nThe \"file:content\" specific widget definition is contributed here to use a custom label \"label.summary.download.file\" instead of the one that would have been generated for the \"content\" generic widget definition: \"label.file.content\".\n\n_Note that in both cases (generic and specific) you don't need to define the widget field definitions since they are automatically computed from the property xpath, except in particular cases like \"note:note\" where the \"mime-type\" field is needed._\n\n##### List and complex properties\n\nYou might already know that the widgets used to display list and complex properties have subwidgets.\nIn the case of a list property, a subwidget is needed for the list items; in the case of a complex property, a subwidget is needed for each item of the complex property.\nThe lookup done by the `DiffDisplayService_` for the first-level widgets is also done recursively for the subwidgets!\n\n###### List property\n\nFor a list property, lets take the example of \"dublincore:contributors\", which is a string list.\n\n- To display the list, nothing special is needed so the \"scalarList\" generic widget definition can be used.\n\n- To display a list item (a contributor, which is of type \"string\"), the \"string\" generic widget definition doesn't match our needs: it would display the contributor's username whereas we want to display its fullname (firstname lastname).\nSo we need a specific widget definition for the list items subwidget to use a custom template able to display the contributor's fullname.\nThe name of this widget definition must match the xpath of the list item property, ie. \"dublincore:contributors/item\".\n\nTherefore, two widget definitions are involved:\n\n- The \"scalarList\" generic widget definition:\n\n```xml\n<widget name=\"scalarList\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"displayAllItems\">false</property>\n    <property name=\"displayItemIndexes\">true</property>\n    <property name=\"template\">\n      /widgets/list_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"dublincore:contributors/item\" specific widget definition:\n\n```xml\n<widget name=\"dublincore:contributors/item\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.dublincore.contributors.item</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"template\">/widgets/contributors_item_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n###### Complex property\n\nFor a complex property, lets take the example of a \"complextypes:complex\" property with two items \"stringItem\" and \"directoryItem\".\n\"stringItem\" is a simple string, but \"directoryItem\" is a string that needs to be bound to the \"myDirectory\" directory.\n\n- To display the complex property, nothing special is needed so the \"complex\" generic widget definition can be used.\n\n- To display the \"directoryItem\" item, the \"string\" generic widget definition doesn't match our needs: it would display the directory entry code stored in the backend whereas we want to display its label.\nSo we need a specific widget definition for the \"directoryItem\" subwidget to use the \"selectOneDirectory\" widget type bound to the \"myDirectory\" directory.\nAs for a list item, the name of this widget definition must match the xpath of the complex property item, ie. \"complextypes:complex/directoryItem\".\n\nTherefore, two widget definitions are involved:\n\n- The \"complex\" generic widget definition:\n\n```xml\n<widget name=\"complex\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"template\">\n      /widgets/complex_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"complextypes:complex/directoryItem\" specific widget definition:\n\n```xml\n<widget name=\"complextypes:complex/directoryItem\" type=\"selectOneDirectory\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.complextypes.complex.directoryItem</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"directoryName\">myDirectory</property>\n    <property name=\"localize\">true</property>\n    <property name=\"ordering\">ordering,label</property>\n  </properties>\n</widget>\n```\n\n###### Useful widget properties\n\nYou can use the following properties on a list widget definition (typically \"scalarList\", \"complexList\" or \"files:files\"):\n\n`<property name=\"displayAllItems\">[true|false]</property>`\nIf set to `true`, all the list items will be displayed, otherwise only the different ones will be.\n\n`<property name=\"displayItemIndexes\">[true|false]</property>`\nIf set to `true`, a subwidget will be added to the widget definition to display the list item indexes.\n\nYou can use the following property on a complex widget definition (typically \"complex\"):\n\n`<property name=\"display\">[inline|*]</property>`\nIf set to `inline` the complex items will be displayed as a table with one line and one column per item, otherwise as a table with one column and one line per item.\n\n##### About the value bound to the diff widgets\n\nIf you take a look at [layout_diff_template.xhtml](nuxeo-diff-jsf/src/main/resources/web/nuxeo.war/layouts/layout_diff_template.xhtml), you will see that the `value` passed to the `<nxl:widget>` tag is `#{value.leftValue}` or `#{value.rightValue}`, `value` being the object passed to the `<nxl:layout>` tag `value` attribute: `diffDisplayBlock`, of type `DiffDisplayBlockImpl`.\nThe `leftValue` and `rightValue` members of `DiffDisplayBlockImpl` are of type `Map<String, Map<String, PropertyDiffDisplay>>`. The first level Map keys are schema names, the second level ones are field keys.\nFinally, the `PropertyDiffDisplay` object has two members: `value` and `styleClass`, `value` holding the value to display and `styleClass` the css style class to apply to the &lt;span&gt; wrapping the value.\n\nFor example if we compare two documents where only the \"dublincore:title\" property is different (\"My first doc\" and \"My second doc\") we could have the following `diffDisplayBlock` object:\n\n```java\ndiffDisplayBlock.getLeftValue() = {dublincore={title={value=\"My first doc\", styleClass=\"redBackgroundColor\"}}}\ndiffDisplayBlock.getRightValue() = {dublincore={title={value=\"My second doc\", styleClass=\"greenBackgroundColor\"}}}\n```\n\nOn the widget side, the field definitions must match the `diffDisplayBlock` object structure, that's why the generated field definitions of the widget used for \"dublincore:title\" would be:\n\n```xml\n<fields>\n  <field>dublincore:title/value</field>\n  <field>dublincore:title/styleClass</field>\n</fields>\n```\n\nThis is important to know when designing a custom template for a diff widget (ie. where field definitions are automatically generated): you can use `#{field_0}` for the value itself and `#{field_1`} for the css style class associated to the value.\nBy default, only the items of a complex property or of a list property where the `displayAllItems` widget property is `true` can have a styleClass equal to `redBackgroundColor` or `greenBackgroundColor` in order to highlight the different items among all.\n\n#### To summarize: what you need to contribute to have a nice diff result for your custom document types\n\n- A `diffDisplay` contribution for each document type.\n\n- The associated `diffBlock` contributions. Don't forget that you can specify the items you want to display for a complex property and the fields/items for which you want to display the content diff links.\n\n- The specific widgets needed when the generic ones don't match your needs. Typically for a date property if you need to change the date format, or for a property bound to a directory to specifiy the directory name. Also don't forget that you can contribute a specific widget for a complex property item or a list item, using the item xpath.\n\n- The labels for each `diffBlock`, each widget and each subwidget in your `messages*.properties` files.\nFor example:\n\n```\nlabel.diffBlock.custom=My custom diff block title\nlabel.customSchema.customField=Custom field\nlabel.customSchema.customField.firstComplexItem=First item of the complex custom field\n```\n\n### Content diff\n\nWork in progress!\n\n# About Nuxeo\n\nNuxeo dramatically improves how content-based applications are built, managed and deployed, making customers more agile, innovative and successful. Nuxeo provides a next generation, enterprise ready platform for building traditional and cutting-edge content oriented applications. Combining a powerful application development environment with SaaS-based tools and a modular architecture, the Nuxeo Platform and Products provide clear business value to some of the most recognizable brands including Verizon, Electronic Arts, Sharp, FICO, the U.S. Navy, and Boeing. Nuxeo is headquartered in New York and Paris. More information is available at www.nuxeo.com.\n",
        "digest": "56f1f6c0b7c5c1f67502f8718bf655e4",
        "encoding": "UTF-8",
        "length": 16731,
        "mimeType": "text/plain",
        "name": "README.md"
      },
      "requirements": [],
      "version": "2023.25.10"
    },
    {
      "@type": "NXBundle",
      "artifactId": "nuxeo-diff-jsf",
      "artifactVersion": "2023.25.10",
      "bundleGroup": {
        "@type": "NXBundleGroup",
        "bundleIds": [
          "org.nuxeo.diff.content",
          "org.nuxeo.diff.core",
          "org.nuxeo.diff.jsf"
        ],
        "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff",
        "id": "grp:org.nuxeo.diff",
        "name": "org.nuxeo.diff",
        "parentIds": [
          "grp:org.nuxeo.ecm"
        ],
        "readmes": [
          {
            "blobProviderId": "default",
            "content": "# Nuxeo Diff\n\nThis repo hosts the source code of a plugin for Nuxeo Platform that allows to render a diff between two documents or two versions of a document.\nThe comparison takes into account all the properties shared by the documents, which means that if a comparison is done between two documents of a different type, only the schemas in common will be \"diffed\".\nThe comparison also takes into account blob-type properties.\n\n\n## Building and deploying\n\n    mvn clean install\n\n## Deploying\n\nInstall [the Nuxeo Diff Marketplace Package](https://connect.nuxeo.com/nuxeo/site/marketplace/package/nuxeo-diff).\n\n## Configuring\n\n### Diff display\n\nThe `DiffDisplayService` offers several extension points to configure the document diff display.\nMost of the code samples exposed here can be found in the [diff-display-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-display-contrib.xml) and [diff-widgets-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-widgets-contrib.xml) files.\n\n#### Configuring groups of properties to display with the diffDisplay extension point.\n\nA `diffDisplay` contribution represents a number of `diffBlocks` that you want to display when asking for a document comparison.\nIt is bound to a document type.\nA `diffBlock` contribution represents a number of properties (fields) that you want to display (see next section).\n\nWhen asking for the comparison between 2 versions of a document, the `diffDisplay` bound to the document type or a super type is used.\nIf no `diffDisplay` is found for this type or a super type a fall back is done on the default diff display mode: one block per document schema and for each block all the fields of the schema that are different.\n\n*Beware that in this case the order of the schemas and of the fields is undefined.*\n\nWhen asking for the comparison between 2 documents:\n- If they are of the same type: if  a `diffDisplay` is found for this type or a super type then it is used, else a fall back is done on the default diff display mode.\n- If they are of different types: if  a `diffDisplay` is found for a common super type then it is used, else a fall back is done on the default diff display mode.\n\nFor example, this is the `diffDisplay` contribution bound to the _File_ type:\n```xml\n<diffDisplay type=\"File\">\n  <diffBlocks>\n    <diffBlock name=\"heading\" />\n    <diffBlock name=\"dublincore\" />\n    <diffBlock name=\"files\" />\n  </diffDisplay>\n</diffBlocks>\n```\n\n_Note that the order of the diffBlocks is taken into account when rendering the diff display._\n\n#### Configuring a group of properties to display with the diffBlock extension point\n\nA `diffBlock` contribution represents a number of `fields` that you want to display. It is rendered as a foldable box.\nThe `label` attribute of a `diffBlock` contribution is used as the title of the foldable box.\nA `field` is defined by its `schema` and its `name`.\n\nFor example, this is the \"heading\" `diffBlock` contribution:\n```xml\n<diffBlock name=\"heading\" label=\"label.diffBlock.heading\">\n  <fields>\n    <field schema=\"dublincore\" name=\"title\" />\n    <field schema=\"dublincore\" name=\"description\" />\n  </fields>\n</diffBlock>\n```\n_Note that the order of the fields is taken into account when rendering the diff block._\n\nFor complex properties, you can contribute inside the `field` element the property `items` that you want to display:\n```xml\n<field schema=\"complextypes\" name=\"complex\">\n  <items>\n    <item name=\"stringItem\" />\n    <item name=\"thirdItem\" />\n    <item name=\"fourthItem\" />\n  </items>\n</field>\n```\n\n_Note that the order of the items is taken into account when rendering the field._\n\nThis is used for the `files` field of the `files` diff block:\n```xml\n<field schema=\"files\" name=\"files\">\n  <items>\n    <!-- Display the file only, not the filename which is managed\n         by the file widget type -->\n    <item name=\"file\" displayContentDiffLinks=\"true\" />\n  </items>\n</field>\n```\n\nIf no `items` are specified, all the property items are displayed.\n\nFor content properties (that hold a blob) or string ones you can set the `displayContentDiffLinks` attribute to `true` on a `field` or an `item` to display the content diff links.\nThese links will open a fancybox showing the detailed content diff using the usual green and red colors to distinguish the added/removed parts of the content.\nFor now, 2 links are displayed: _Textual diff_ based on a text conversion and _Html diff_ based on an html conversion (keeps the content layout).\n\n#### Configuring property widgets with the widgets extension point\n\n##### Principle\n\nWhen rendering a `diffBlock`, the `DiffDisplayService` builds a layout definition on the fly, including a layout row for each `field` of the `diffBlock`.\nEach row contains a widget definition for the `field`, and the layout template renders 2 instances of this widget definition: one for the left document and one for the right document.\nThe content diff links, if displayed, are also rendered by a widget inside the layout row.\n\nHow is the widget definition built for a given `field`?\nA lookup is done in the `LayoutStore` service to find a specific widget definition named with the xpath of the property.\nIf such a definition is not found, a lookup is done to find a generic widget definition named with the type of the property.\n\nThis allows you to only contribute a specific widget definition if the generic one doesn't match your needs for a given field, typically if you need a custom template, label or custom properties.\n\n##### Example\n\nLets say we have contributed the following `diffBlock`:\n```xml\n<diffBlock name=\"myCustomBlock\" label=\"label.diffBlock.custom\">\n  <fields>\n    <field schema=\"file\" name=\"content\" />\n    <field schema=\"dublincore\" name=\"title\" />\n  </fields>\n</diffBlock>\n```\n\nand the following widgets to the `widgets` extension point of the `org.nuxeo.ecm.platform.forms.layout.LayoutStore` component:\n```xml\n<extension target=\"org.nuxeo.ecm.platform.forms.layout.LayoutStore\"\n  point=\"widgets\">\n\n  <widget name=\"file:content\" type=\"file\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <labels>\n      <label mode=\"any\">label.summary.download.file</label>\n    </labels>\n    <translated>true</translated>\n    <properties mode=\"any\">\n    </properties>\n  </widget>\n\n  <widget name=\"string\" type=\"template\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <properties mode=\"any\">\n      <property name=\"widgetType\">text</property>\n      <property name=\"template\">\n        /widgets/generic_diff_widget_template.xhtml\n      </property>\n    </properties>\n  </widget>\n\n</extension>\n```\n\nWhen rendering the \"myCustomBlock\" `diffBlock`, the `DiffDisplayService` will:\n\n- Look for a specific widget definition named \"file:content\" in the `LayoutStore`, find it and use it for the \"file:content\" field.\n\n- Look for a specific widget definition named \"dublincore:title\" in the `LayoutStore`, won't find it and therefore will look for a generic widget definition named with the field type, ie. \"string\", find it and use it for the dublincore:title field.\n\nIn this use case, the \"string\" generic widget definition is sufficient to display the \"dublincore:title\" field.\nIt uses a widget of type \"text\" with \"label.dublincore.title\" as a label and \"dublincore:title\" as a field definition.\nWe can easily understand here the interest of generic widgets: once you have the type and xpath of a property, the matching widget definition can be computed on the fly using the property type to guess the widget type (\"string\" => \"text\", \"date\" => \"datetime\", etc.) and the property xpath for the field definition and label.\n\nThe \"file:content\" specific widget definition is contributed here to use a custom label \"label.summary.download.file\" instead of the one that would have been generated for the \"content\" generic widget definition: \"label.file.content\".\n\n_Note that in both cases (generic and specific) you don't need to define the widget field definitions since they are automatically computed from the property xpath, except in particular cases like \"note:note\" where the \"mime-type\" field is needed._\n\n##### List and complex properties\n\nYou might already know that the widgets used to display list and complex properties have subwidgets.\nIn the case of a list property, a subwidget is needed for the list items; in the case of a complex property, a subwidget is needed for each item of the complex property.\nThe lookup done by the `DiffDisplayService_` for the first-level widgets is also done recursively for the subwidgets!\n\n###### List property\n\nFor a list property, lets take the example of \"dublincore:contributors\", which is a string list.\n\n- To display the list, nothing special is needed so the \"scalarList\" generic widget definition can be used.\n\n- To display a list item (a contributor, which is of type \"string\"), the \"string\" generic widget definition doesn't match our needs: it would display the contributor's username whereas we want to display its fullname (firstname lastname).\nSo we need a specific widget definition for the list items subwidget to use a custom template able to display the contributor's fullname.\nThe name of this widget definition must match the xpath of the list item property, ie. \"dublincore:contributors/item\".\n\nTherefore, two widget definitions are involved:\n\n- The \"scalarList\" generic widget definition:\n\n```xml\n<widget name=\"scalarList\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"displayAllItems\">false</property>\n    <property name=\"displayItemIndexes\">true</property>\n    <property name=\"template\">\n      /widgets/list_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"dublincore:contributors/item\" specific widget definition:\n\n```xml\n<widget name=\"dublincore:contributors/item\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.dublincore.contributors.item</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"template\">/widgets/contributors_item_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n###### Complex property\n\nFor a complex property, lets take the example of a \"complextypes:complex\" property with two items \"stringItem\" and \"directoryItem\".\n\"stringItem\" is a simple string, but \"directoryItem\" is a string that needs to be bound to the \"myDirectory\" directory.\n\n- To display the complex property, nothing special is needed so the \"complex\" generic widget definition can be used.\n\n- To display the \"directoryItem\" item, the \"string\" generic widget definition doesn't match our needs: it would display the directory entry code stored in the backend whereas we want to display its label.\nSo we need a specific widget definition for the \"directoryItem\" subwidget to use the \"selectOneDirectory\" widget type bound to the \"myDirectory\" directory.\nAs for a list item, the name of this widget definition must match the xpath of the complex property item, ie. \"complextypes:complex/directoryItem\".\n\nTherefore, two widget definitions are involved:\n\n- The \"complex\" generic widget definition:\n\n```xml\n<widget name=\"complex\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"template\">\n      /widgets/complex_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"complextypes:complex/directoryItem\" specific widget definition:\n\n```xml\n<widget name=\"complextypes:complex/directoryItem\" type=\"selectOneDirectory\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.complextypes.complex.directoryItem</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"directoryName\">myDirectory</property>\n    <property name=\"localize\">true</property>\n    <property name=\"ordering\">ordering,label</property>\n  </properties>\n</widget>\n```\n\n###### Useful widget properties\n\nYou can use the following properties on a list widget definition (typically \"scalarList\", \"complexList\" or \"files:files\"):\n\n`<property name=\"displayAllItems\">[true|false]</property>`\nIf set to `true`, all the list items will be displayed, otherwise only the different ones will be.\n\n`<property name=\"displayItemIndexes\">[true|false]</property>`\nIf set to `true`, a subwidget will be added to the widget definition to display the list item indexes.\n\nYou can use the following property on a complex widget definition (typically \"complex\"):\n\n`<property name=\"display\">[inline|*]</property>`\nIf set to `inline` the complex items will be displayed as a table with one line and one column per item, otherwise as a table with one column and one line per item.\n\n##### About the value bound to the diff widgets\n\nIf you take a look at [layout_diff_template.xhtml](nuxeo-diff-jsf/src/main/resources/web/nuxeo.war/layouts/layout_diff_template.xhtml), you will see that the `value` passed to the `<nxl:widget>` tag is `#{value.leftValue}` or `#{value.rightValue}`, `value` being the object passed to the `<nxl:layout>` tag `value` attribute: `diffDisplayBlock`, of type `DiffDisplayBlockImpl`.\nThe `leftValue` and `rightValue` members of `DiffDisplayBlockImpl` are of type `Map<String, Map<String, PropertyDiffDisplay>>`. The first level Map keys are schema names, the second level ones are field keys.\nFinally, the `PropertyDiffDisplay` object has two members: `value` and `styleClass`, `value` holding the value to display and `styleClass` the css style class to apply to the &lt;span&gt; wrapping the value.\n\nFor example if we compare two documents where only the \"dublincore:title\" property is different (\"My first doc\" and \"My second doc\") we could have the following `diffDisplayBlock` object:\n\n```java\ndiffDisplayBlock.getLeftValue() = {dublincore={title={value=\"My first doc\", styleClass=\"redBackgroundColor\"}}}\ndiffDisplayBlock.getRightValue() = {dublincore={title={value=\"My second doc\", styleClass=\"greenBackgroundColor\"}}}\n```\n\nOn the widget side, the field definitions must match the `diffDisplayBlock` object structure, that's why the generated field definitions of the widget used for \"dublincore:title\" would be:\n\n```xml\n<fields>\n  <field>dublincore:title/value</field>\n  <field>dublincore:title/styleClass</field>\n</fields>\n```\n\nThis is important to know when designing a custom template for a diff widget (ie. where field definitions are automatically generated): you can use `#{field_0}` for the value itself and `#{field_1`} for the css style class associated to the value.\nBy default, only the items of a complex property or of a list property where the `displayAllItems` widget property is `true` can have a styleClass equal to `redBackgroundColor` or `greenBackgroundColor` in order to highlight the different items among all.\n\n#### To summarize: what you need to contribute to have a nice diff result for your custom document types\n\n- A `diffDisplay` contribution for each document type.\n\n- The associated `diffBlock` contributions. Don't forget that you can specify the items you want to display for a complex property and the fields/items for which you want to display the content diff links.\n\n- The specific widgets needed when the generic ones don't match your needs. Typically for a date property if you need to change the date format, or for a property bound to a directory to specifiy the directory name. Also don't forget that you can contribute a specific widget for a complex property item or a list item, using the item xpath.\n\n- The labels for each `diffBlock`, each widget and each subwidget in your `messages*.properties` files.\nFor example:\n\n```\nlabel.diffBlock.custom=My custom diff block title\nlabel.customSchema.customField=Custom field\nlabel.customSchema.customField.firstComplexItem=First item of the complex custom field\n```\n\n### Content diff\n\nWork in progress!\n\n# About Nuxeo\n\nNuxeo dramatically improves how content-based applications are built, managed and deployed, making customers more agile, innovative and successful. Nuxeo provides a next generation, enterprise ready platform for building traditional and cutting-edge content oriented applications. Combining a powerful application development environment with SaaS-based tools and a modular architecture, the Nuxeo Platform and Products provide clear business value to some of the most recognizable brands including Verizon, Electronic Arts, Sharp, FICO, the U.S. Navy, and Boeing. Nuxeo is headquartered in New York and Paris. More information is available at www.nuxeo.com.\n",
            "digest": "56f1f6c0b7c5c1f67502f8718bf655e4",
            "encoding": "UTF-8",
            "length": 16731,
            "mimeType": "text/plain",
            "name": "README.md"
          }
        ],
        "version": "2023.25"
      },
      "bundleId": "org.nuxeo.diff.jsf",
      "components": [
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.platform.actions.ActionService--actions",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.actions/Contributions/org.nuxeo.ecm.diff.actions--actions",
              "id": "org.nuxeo.ecm.diff.actions--actions",
              "registrationOrder": 4,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.platform.actions.ActionService",
                "name": "org.nuxeo.ecm.platform.actions.ActionService",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"actions\" target=\"org.nuxeo.ecm.platform.actions.ActionService\">\n\n    <!-- Current selection actions -->\n    <action id=\"CURRENT_DOCUMENT_SELECTION_DIFF\" label=\"command.clipboard.diff\" link=\"#{diffActions.prepareCurrentDocumentSelectionDiff}\" order=\"100\">\n      <category>CURRENT_SELECTION_LIST</category>\n      <category>ORDERABLE_CURRENT_SELECTION_LIST</category>\n      <filter-id>canDiffCurrentDocumentSelection</filter-id>\n    </action>\n\n    <!-- Trash actions -->\n    <action id=\"CURRENT_TRASH_SELECTION_DIFF\" label=\"command.clipboard.diff\" link=\"#{diffActions.prepareCurrentTrashSelectionDiff}\" order=\"100\">\n      <category>CURRENT_SELECTION_TRASH_LIST</category>\n      <filter-id>canDiffCurrentTrashSelection</filter-id>\n    </action>\n\n    <!-- Section actions -->\n    <action id=\"CURRENT_SECTION_SELECTION_DIFF\" label=\"command.clipboard.diff\" link=\"#{diffActions.prepareCurrentSectionSelectionDiff}\" order=\"100\">\n      <category>CURRENT_SELECTION_SECTIONS_LIST</category>\n      <filter-id>canDiffCurrentSectionSelection</filter-id>\n    </action>\n\n    <!-- Worklist actions -->\n    <action icon=\"/icons/action_diff.png\" id=\"CURRENT_DEFAULT_SELECTION_DIFF\" label=\"command.clipboard.diff\" link=\"#{diffActions.prepareCurrentDefaultSelectionDiff}\" order=\"100\">\n      <category>DEFAULT_LIST</category>\n      <filter-id>canDiffCurrentDefaultSelection</filter-id>\n    </action>\n\n    <!-- Version actions -->\n    <action id=\"CURRENT_VERSION_SELECTION_DIFF\" label=\"command.clipboard.diff\" link=\"#{diffActions.prepareCurrentVersionSelectionDiff}\" order=\"100\">\n      <category>CURRENT_VERSION_SELECTION_LIST</category>\n      <filter-id>canDiffCurrentVersionSelection</filter-id>\n    </action>\n\n    <action id=\"CURRENT_VERSION_DIFF\" label=\"command.versions.diffCurrent\" link=\"#{diffActions.prepareCurrentVersionDiff}\" order=\"100\">\n      <category>VERSION_LIST_ITEM</category>\n    </action>\n\n  </extension>"
            },
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.platform.actions.ActionService--filters",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.actions/Contributions/org.nuxeo.ecm.diff.actions--filters",
              "id": "org.nuxeo.ecm.diff.actions--filters",
              "registrationOrder": 2,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.platform.actions.ActionService",
                "name": "org.nuxeo.ecm.platform.actions.ActionService",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"filters\" target=\"org.nuxeo.ecm.platform.actions.ActionService\">\n\n    <filter id=\"canDiffCurrentDocumentSelection\">\n      <rule grant=\"true\">\n        <condition>#{diffActions.canDiffCurrentDocumentSelection}\n        </condition>\n      </rule>\n    </filter>\n\n    <filter id=\"canDiffCurrentTrashSelection\">\n      <rule grant=\"true\">\n        <condition>#{diffActions.canDiffCurrentTrashSelection}\n        </condition>\n      </rule>\n    </filter>\n\n    <filter id=\"canDiffCurrentSectionSelection\">\n      <rule grant=\"true\">\n        <condition>#{diffActions.canDiffCurrentSectionSelection}\n        </condition>\n      </rule>\n    </filter>\n\n    <filter id=\"canDiffCurrentVersionSelection\">\n      <rule grant=\"true\">\n        <condition>#{diffActions.canDiffCurrentVersionSelection}\n        </condition>\n      </rule>\n    </filter>\n\n    <filter id=\"canDiffCurrentDefaultSelection\">\n      <rule grant=\"true\">\n        <condition>#{diffActions.canDiffCurrentDefaultSelection}\n        </condition>\n      </rule>\n    </filter>\n\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.actions",
          "name": "org.nuxeo.ecm.diff.actions",
          "requirements": [],
          "resolutionOrder": 179,
          "services": [],
          "startOrder": 189,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.actions\">\n\n  <extension target=\"org.nuxeo.ecm.platform.actions.ActionService\"\n    point=\"actions\">\n\n    <!-- Current selection actions -->\n    <action id=\"CURRENT_DOCUMENT_SELECTION_DIFF\"\n      link=\"#{diffActions.prepareCurrentDocumentSelectionDiff}\" label=\"command.clipboard.diff\"\n      order=\"100\">\n      <category>CURRENT_SELECTION_LIST</category>\n      <category>ORDERABLE_CURRENT_SELECTION_LIST</category>\n      <filter-id>canDiffCurrentDocumentSelection</filter-id>\n    </action>\n\n    <!-- Trash actions -->\n    <action id=\"CURRENT_TRASH_SELECTION_DIFF\" link=\"#{diffActions.prepareCurrentTrashSelectionDiff}\"\n      label=\"command.clipboard.diff\" order=\"100\">\n      <category>CURRENT_SELECTION_TRASH_LIST</category>\n      <filter-id>canDiffCurrentTrashSelection</filter-id>\n    </action>\n\n    <!-- Section actions -->\n    <action id=\"CURRENT_SECTION_SELECTION_DIFF\"\n      link=\"#{diffActions.prepareCurrentSectionSelectionDiff}\" label=\"command.clipboard.diff\"\n      order=\"100\">\n      <category>CURRENT_SELECTION_SECTIONS_LIST</category>\n      <filter-id>canDiffCurrentSectionSelection</filter-id>\n    </action>\n\n    <!-- Worklist actions -->\n    <action id=\"CURRENT_DEFAULT_SELECTION_DIFF\"\n      link=\"#{diffActions.prepareCurrentDefaultSelectionDiff}\" label=\"command.clipboard.diff\"\n      icon=\"/icons/action_diff.png\" order=\"100\">\n      <category>DEFAULT_LIST</category>\n      <filter-id>canDiffCurrentDefaultSelection</filter-id>\n    </action>\n\n    <!-- Version actions -->\n    <action id=\"CURRENT_VERSION_SELECTION_DIFF\"\n      link=\"#{diffActions.prepareCurrentVersionSelectionDiff}\" label=\"command.clipboard.diff\"\n      order=\"100\">\n      <category>CURRENT_VERSION_SELECTION_LIST</category>\n      <filter-id>canDiffCurrentVersionSelection</filter-id>\n    </action>\n\n    <action id=\"CURRENT_VERSION_DIFF\" link=\"#{diffActions.prepareCurrentVersionDiff}\"\n      label=\"command.versions.diffCurrent\" order=\"100\">\n      <category>VERSION_LIST_ITEM</category>\n    </action>\n\n  </extension>\n\n  <extension target=\"org.nuxeo.ecm.platform.actions.ActionService\"\n    point=\"filters\">\n\n    <filter id=\"canDiffCurrentDocumentSelection\">\n      <rule grant=\"true\">\n        <condition>#{diffActions.canDiffCurrentDocumentSelection}\n        </condition>\n      </rule>\n    </filter>\n\n    <filter id=\"canDiffCurrentTrashSelection\">\n      <rule grant=\"true\">\n        <condition>#{diffActions.canDiffCurrentTrashSelection}\n        </condition>\n      </rule>\n    </filter>\n\n    <filter id=\"canDiffCurrentSectionSelection\">\n      <rule grant=\"true\">\n        <condition>#{diffActions.canDiffCurrentSectionSelection}\n        </condition>\n      </rule>\n    </filter>\n\n    <filter id=\"canDiffCurrentVersionSelection\">\n      <rule grant=\"true\">\n        <condition>#{diffActions.canDiffCurrentVersionSelection}\n        </condition>\n      </rule>\n    </filter>\n\n    <filter id=\"canDiffCurrentDefaultSelection\">\n      <rule grant=\"true\">\n        <condition>#{diffActions.canDiffCurrentDefaultSelection}\n        </condition>\n      </rule>\n    </filter>\n\n  </extension>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/diff-actions-contrib.xml",
          "xmlPureComponent": true
        },
        {
          "@type": "NXComponent",
          "componentClass": "org.nuxeo.ecm.diff.service.impl.DiffDisplayServiceImpl",
          "documentation": "\n    This service provides an extension point to manage\n    document diff display.\n\n    @author\n    Antoine Taillefer\n  \n",
          "documentationHtml": "<p>\nThis service provides an extension point to manage\ndocument diff display.\n</p><p>\nAntoine Taillefer\n</p><p></p>",
          "extensionPoints": [
            {
              "@type": "NXExtensionPoint",
              "componentId": "org.nuxeo.ecm.diff.service.DiffDisplayService",
              "descriptors": [
                "org.nuxeo.ecm.diff.service.impl.DiffExcludedFieldsDescriptor",
                "org.nuxeo.ecm.diff.service.impl.DiffComplexFieldDescriptor"
              ],
              "documentation": "<pre>\n        The diffDefaultDisplay extension point allows you to\n        contribute a diffExcludedFields contribution to define a\n        set of\n        fields from a given schema that will be\n        excluded from the default\n        diff display in the document diff view\n        (the default diff display\n        takes into account every different field of every common schema\n        between the compared\n        documents, in an undefined order).\n\n        If no\n        fields are specified, the whole schema is excluded.\n      </pre>\n<code>\n    <diffExcludedFields schema=\"common\"/>\n    <diffExcludedFields schema=\"dublincore\">\n        <fields>\n            <field name=\"subjects\"/>\n            <field name=\"modified\"/>\n        </fields>\n    </diffExcludedFields>\n</code>\n",
              "documentationHtml": "<p>\n</p><pre>\nThe diffDefaultDisplay extension point allows you to\ncontribute a diffExcludedFields contribution to define a\nset of\nfields from a given schema that will be\nexcluded from the default\ndiff display in the document diff view\n(the default diff display\ntakes into account every different field of every common schema\nbetween the compared\ndocuments, in an undefined order).\n<p>\nIf no\nfields are specified, the whole schema is excluded.\n</p></pre>\n<p></p><pre><code>    &lt;diffExcludedFields schema&#61;&#34;common&#34;/&gt;\n    &lt;diffExcludedFields schema&#61;&#34;dublincore&#34;&gt;\n        &lt;fields&gt;\n            &lt;field name&#61;&#34;subjects&#34;/&gt;\n            &lt;field name&#61;&#34;modified&#34;/&gt;\n        &lt;/fields&gt;\n    &lt;/diffExcludedFields&gt;\n</code></pre><p></p>",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.service.DiffDisplayService/ExtensionPoints/org.nuxeo.ecm.diff.service.DiffDisplayService--diffDefaultDisplay",
              "id": "org.nuxeo.ecm.diff.service.DiffDisplayService--diffDefaultDisplay",
              "label": "diffDefaultDisplay (org.nuxeo.ecm.diff.service.DiffDisplayService)",
              "name": "diffDefaultDisplay",
              "version": "2023.25.10"
            },
            {
              "@type": "NXExtensionPoint",
              "componentId": "org.nuxeo.ecm.diff.service.DiffDisplayService",
              "descriptors": [
                "org.nuxeo.ecm.diff.service.impl.DiffDisplayDescriptor"
              ],
              "documentation": "<pre>\n        A diffDisplay contribution defines which diffBlocks will be\n        displayed in the document diff view for a given\n        document type.\n        The order matters.\n\n        If the 2 diffed documents have the same type,\n        the diffDisplay matching this type\n        is used, otherwise or if such\n        a diffDisplay does not exist, the default diff display is used.\n        The default diff\n        display\n        takes into account every different field\n        of every common schema between the\n        compared documents, in an\n        undefined order.\n      </pre>\n<code>\n    <diffDisplay type=\"File\">\n        <diffBlocks>\n            <diffBlock name=\"dublincore\"/>\n            <diffBlock name=\"files\"/>\n        </diffBlocks>\n    </diffDisplay>\n    <diffDisplay enabled=\"false\" type=\"Note\"/>\n</code>\n",
              "documentationHtml": "<p>\n</p><pre>\nA diffDisplay contribution defines which diffBlocks will be\ndisplayed in the document diff view for a given\ndocument type.\nThe order matters.\n<p>\nIf the 2 diffed documents have the same type,\nthe diffDisplay matching this type\nis used, otherwise or if such\na diffDisplay does not exist, the default diff display is used.\nThe default diff\ndisplay\ntakes into account every different field\nof every common schema between the\ncompared documents, in an\nundefined order.\n</p></pre>\n<p></p><pre><code>    &lt;diffDisplay type&#61;&#34;File&#34;&gt;\n        &lt;diffBlocks&gt;\n            &lt;diffBlock name&#61;&#34;dublincore&#34;/&gt;\n            &lt;diffBlock name&#61;&#34;files&#34;/&gt;\n        &lt;/diffBlocks&gt;\n    &lt;/diffDisplay&gt;\n    &lt;diffDisplay enabled&#61;&#34;false&#34; type&#61;&#34;Note&#34;/&gt;\n</code></pre><p></p>",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.service.DiffDisplayService/ExtensionPoints/org.nuxeo.ecm.diff.service.DiffDisplayService--diffDisplay",
              "id": "org.nuxeo.ecm.diff.service.DiffDisplayService--diffDisplay",
              "label": "diffDisplay (org.nuxeo.ecm.diff.service.DiffDisplayService)",
              "name": "diffDisplay",
              "version": "2023.25.10"
            },
            {
              "@type": "NXExtensionPoint",
              "componentId": "org.nuxeo.ecm.diff.service.DiffDisplayService",
              "descriptors": [
                "org.nuxeo.ecm.diff.service.impl.DiffBlockDescriptor"
              ],
              "documentation": "<pre>\n        A diffBlock contribution defines which fields will be\n        displayed in the diff display block.\n        The order matters.\n\n        For\n        complex types, items can be\n        defined to specifiy which sub-fields\n        must be displayed and in which order.\n      </pre>\n<code>\n    <diffBlock label=\"label.diffBlock.dublincore\" name=\"dublincore\">\n        <fields>\n            <field name=\"description\" schema=\"dublincore\"/>\n            <field name=\"coverage\" schema=\"dublincore\"/>\n            <field name=\"created\" schema=\"dublincore\"/>\n            <field name=\"modified\" schema=\"dublincore\"/>\n        </fields>\n    </diffBlock>\n    <diffBlock label=\"label.diffBlock.files\" name=\"files\">\n        <fields>\n            <field displayContentDiffLinks=\"true\" name=\"content\" schema=\"file\"/>\n            <field name=\"files\" schema=\"files\">\n                <items>\n                    <!-- Display the file only, not the filename which is managed by the file widget type -->\n                    <item displayContentDiffLinks=\"true\" name=\"file\"/>\n                </items>\n            </field>\n        </fields>\n    </diffBlock>\n</code>\n",
              "documentationHtml": "<p>\n</p><pre>\nA diffBlock contribution defines which fields will be\ndisplayed in the diff display block.\nThe order matters.\n<p>\nFor\ncomplex types, items can be\ndefined to specifiy which sub-fields\nmust be displayed and in which order.\n</p></pre>\n<p></p><pre><code>    &lt;diffBlock label&#61;&#34;label.diffBlock.dublincore&#34; name&#61;&#34;dublincore&#34;&gt;\n        &lt;fields&gt;\n            &lt;field name&#61;&#34;description&#34; schema&#61;&#34;dublincore&#34;/&gt;\n            &lt;field name&#61;&#34;coverage&#34; schema&#61;&#34;dublincore&#34;/&gt;\n            &lt;field name&#61;&#34;created&#34; schema&#61;&#34;dublincore&#34;/&gt;\n            &lt;field name&#61;&#34;modified&#34; schema&#61;&#34;dublincore&#34;/&gt;\n        &lt;/fields&gt;\n    &lt;/diffBlock&gt;\n    &lt;diffBlock label&#61;&#34;label.diffBlock.files&#34; name&#61;&#34;files&#34;&gt;\n        &lt;fields&gt;\n            &lt;field displayContentDiffLinks&#61;&#34;true&#34; name&#61;&#34;content&#34; schema&#61;&#34;file&#34;/&gt;\n            &lt;field name&#61;&#34;files&#34; schema&#61;&#34;files&#34;&gt;\n                &lt;items&gt;\n                    &lt;!-- Display the file only, not the filename which is managed by the file widget type --&gt;\n                    &lt;item displayContentDiffLinks&#61;&#34;true&#34; name&#61;&#34;file&#34;/&gt;\n                &lt;/items&gt;\n            &lt;/field&gt;\n        &lt;/fields&gt;\n    &lt;/diffBlock&gt;\n</code></pre><p></p>",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.service.DiffDisplayService/ExtensionPoints/org.nuxeo.ecm.diff.service.DiffDisplayService--diffBlock",
              "id": "org.nuxeo.ecm.diff.service.DiffDisplayService--diffBlock",
              "label": "diffBlock (org.nuxeo.ecm.diff.service.DiffDisplayService)",
              "name": "diffBlock",
              "version": "2023.25.10"
            }
          ],
          "extensions": [],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.service.DiffDisplayService",
          "name": "org.nuxeo.ecm.diff.service.DiffDisplayService",
          "requirements": [],
          "resolutionOrder": 180,
          "services": [
            {
              "@type": "NXService",
              "componentId": "org.nuxeo.ecm.diff.service.DiffDisplayService",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.service.DiffDisplayService/Services/org.nuxeo.ecm.diff.service.DiffDisplayService",
              "id": "org.nuxeo.ecm.diff.service.DiffDisplayService",
              "overriden": false,
              "version": "2023.25.10"
            }
          ],
          "startOrder": 831,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.service.DiffDisplayService\">\n\n  <documentation>\n    This service provides an extension point to manage\n    document diff display.\n\n    @author\n    Antoine Taillefer\n  </documentation>\n\n  <implementation class=\"org.nuxeo.ecm.diff.service.impl.DiffDisplayServiceImpl\" />\n\n  <service>\n    <provide interface=\"org.nuxeo.ecm.diff.service.DiffDisplayService\" />\n  </service>\n\n  <extension-point name=\"diffDefaultDisplay\">\n\n    <documentation>\n      <pre>\n        The diffDefaultDisplay extension point allows you to\n        contribute a diffExcludedFields contribution to define a\n        set of\n        fields from a given schema that will be\n        excluded from the default\n        diff display in the document diff view\n        (the default diff display\n        takes into account every different field of every common schema\n        between the compared\n        documents, in an undefined order).\n\n        If no\n        fields are specified, the whole schema is excluded.\n      </pre>\n      <code>\n        <diffExcludedFields schema=\"common\" />\n        <diffExcludedFields schema=\"dublincore\">\n          <fields>\n            <field name=\"subjects\" />\n            <field name=\"modified\" />\n          </fields>\n        </diffExcludedFields>\n      </code>\n    </documentation>\n    <object class=\"org.nuxeo.ecm.diff.service.impl.DiffExcludedFieldsDescriptor\" />\n\n    <documentation>\n      <pre>\n        The diffDefaultDisplay extension point also allows you to\n        contribute a diffComplexField contribution to define\n        a set of\n        items from a given complex property that will be\n        included or\n        excluded from the default\n        diff display in the\n        document diff view.\n        Order matters for included items.\n      </pre>\n      <code>\n        <diffComplexField schema=\"complextypes\" name=\"complex\">\n          <includedItems>\n            <item name=\"dateItem\" />\n            <item name=\"stringItem\" />\n          </includedItems>\n        </diffComplexField>\n\n        <diffComplexField schema=\"complextypes\" name=\"complexList\">\n          <excludedItems>\n            <item name=\"stringItem\" />\n            <item name=\"dateItem\" />\n          </excludedItems>\n        </diffComplexField>\n      </code>\n    </documentation>\n    <object class=\"org.nuxeo.ecm.diff.service.impl.DiffComplexFieldDescriptor\" />\n\n  </extension-point>\n\n\n  <extension-point name=\"diffDisplay\">\n    <documentation>\n\n      <pre>\n        A diffDisplay contribution defines which diffBlocks will be\n        displayed in the document diff view for a given\n        document type.\n        The order matters.\n\n        If the 2 diffed documents have the same type,\n        the diffDisplay matching this type\n        is used, otherwise or if such\n        a diffDisplay does not exist, the default diff display is used.\n        The default diff\n        display\n        takes into account every different field\n        of every common schema between the\n        compared documents, in an\n        undefined order.\n      </pre>\n\n      <code>\n        <diffDisplay type=\"File\">\n          <diffBlocks>\n            <diffBlock name=\"dublincore\" />\n            <diffBlock name=\"files\" />\n          </diffBlocks>\n        </diffDisplay>\n        <diffDisplay type=\"Note\" enabled=\"false\" />\n      </code>\n\n    </documentation>\n    <object class=\"org.nuxeo.ecm.diff.service.impl.DiffDisplayDescriptor\" />\n  </extension-point>\n\n  <extension-point name=\"diffBlock\">\n    <documentation>\n\n      <pre>\n        A diffBlock contribution defines which fields will be\n        displayed in the diff display block.\n        The order matters.\n\n        For\n        complex types, items can be\n        defined to specifiy which sub-fields\n        must be displayed and in which order.\n      </pre>\n\n      <code>\n        <diffBlock name=\"dublincore\" label=\"label.diffBlock.dublincore\">\n          <fields>\n            <field schema=\"dublincore\" name=\"description\" />\n            <field schema=\"dublincore\" name=\"coverage\" />\n            <field schema=\"dublincore\" name=\"created\" />\n            <field schema=\"dublincore\" name=\"modified\" />\n          </fields>\n        </diffBlock>\n        <diffBlock name=\"files\" label=\"label.diffBlock.files\">\n          <fields>\n            <field schema=\"file\" name=\"content\" displayContentDiffLinks=\"true\" />\n            <field schema=\"files\" name=\"files\">\n              <items>\n                <!-- Display the file only, not the filename which is managed by the file widget type -->\n                <item name=\"file\" displayContentDiffLinks=\"true\" />\n              </items>\n            </field>\n          </fields>\n        </diffBlock>\n      </code>\n\n    </documentation>\n    <object class=\"org.nuxeo.ecm.diff.service.impl.DiffBlockDescriptor\" />\n  </extension-point>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/diff-display-service.xml",
          "xmlPureComponent": false
        },
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.diff.service.DiffDisplayService--diffDefaultDisplay",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.service.DiffDisplayService.contrib/Contributions/org.nuxeo.ecm.diff.service.DiffDisplayService.contrib--diffDefaultDisplay",
              "id": "org.nuxeo.ecm.diff.service.DiffDisplayService.contrib--diffDefaultDisplay",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.diff.service.DiffDisplayService",
                "name": "org.nuxeo.ecm.diff.service.DiffDisplayService",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"diffDefaultDisplay\" target=\"org.nuxeo.ecm.diff.service.DiffDisplayService\">\n\n    <diffExcludedFields schema=\"common\"/>\n\n  </extension>"
            },
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.diff.service.DiffDisplayService--diffDisplay",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.service.DiffDisplayService.contrib/Contributions/org.nuxeo.ecm.diff.service.DiffDisplayService.contrib--diffDisplay",
              "id": "org.nuxeo.ecm.diff.service.DiffDisplayService.contrib--diffDisplay",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.diff.service.DiffDisplayService",
                "name": "org.nuxeo.ecm.diff.service.DiffDisplayService",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"diffDisplay\" target=\"org.nuxeo.ecm.diff.service.DiffDisplayService\">\n\n    <diffDisplay type=\"Folder\">\n      <diffBlocks>\n        <diffBlock name=\"dublincore\"/>\n      </diffBlocks>\n    </diffDisplay>\n\n    <diffDisplay type=\"File\">\n      <diffBlocks>\n        <diffBlock name=\"dublincore\"/>\n        <diffBlock name=\"files\"/>\n      </diffBlocks>\n    </diffDisplay>\n\n    <diffDisplay type=\"Note\">\n      <diffBlocks>\n        <diffBlock name=\"dublincore\"/>\n        <diffBlock name=\"note\"/>\n        <diffBlock name=\"files\"/>\n      </diffBlocks>\n    </diffDisplay>\n\n  </extension>"
            },
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.diff.service.DiffDisplayService--diffBlock",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.service.DiffDisplayService.contrib/Contributions/org.nuxeo.ecm.diff.service.DiffDisplayService.contrib--diffBlock",
              "id": "org.nuxeo.ecm.diff.service.DiffDisplayService.contrib--diffBlock",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.diff.service.DiffDisplayService",
                "name": "org.nuxeo.ecm.diff.service.DiffDisplayService",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"diffBlock\" target=\"org.nuxeo.ecm.diff.service.DiffDisplayService\">\n\n    <diffBlock name=\"dublincore\">\n      <properties mode=\"any\">\n        <property name=\"label\">label.diffBlock.dublincore</property>\n      </properties>\n      <fields>\n        <field name=\"description\" schema=\"dublincore\"/>\n        <!-- Display the \"dam_common\" schema fields in case the DAM package\n          is installed -->\n        <field name=\"author\" schema=\"dam_common\"/>\n        <field name=\"authoringDate\" schema=\"dam_common\"/>\n        <field name=\"nature\" schema=\"dublincore\"/>\n        <field name=\"subjects\" schema=\"dublincore\"/>\n        <field name=\"rights\" schema=\"dublincore\"/>\n        <field name=\"source\" schema=\"dublincore\"/>\n        <field name=\"coverage\" schema=\"dublincore\"/>\n        <field name=\"created\" schema=\"dublincore\"/>\n        <field name=\"modified\" schema=\"dublincore\"/>\n        <field name=\"format\" schema=\"dublincore\"/>\n        <field name=\"language\" schema=\"dublincore\"/>\n        <field name=\"expired\" schema=\"dublincore\"/>\n        <field name=\"creator\" schema=\"dublincore\"/>\n        <field name=\"contributors\" schema=\"dublincore\"/>\n        <field name=\"lastContributor\" schema=\"dublincore\"/>\n      </fields>\n      <templates>\n        <template mode=\"any\">/layouts/layout_diff_template.xhtml\n        </template>\n      </templates>\n    </diffBlock>\n\n    <diffBlock name=\"files\">\n      <properties mode=\"any\">\n        <property name=\"label\">label.diffBlock.files</property>\n      </properties>\n      <fields>\n        <field displayContentDiffLinks=\"true\" name=\"content\" schema=\"file\"/>\n        <field name=\"files\" schema=\"files\">\n          <items>\n            <!-- Display the file only, not the filename which is managed\n              by the file widget type -->\n            <item displayContentDiffLinks=\"true\" name=\"file\"/>\n          </items>\n        </field>\n      </fields>\n      <templates>\n        <template mode=\"any\">/layouts/layout_diff_template.xhtml\n        </template>\n      </templates>\n    </diffBlock>\n\n    <diffBlock name=\"note\">\n      <properties mode=\"any\">\n        <property name=\"label\">label.diffBlock.note</property>\n      </properties>\n      <fields>\n        <field displayContentDiffLinks=\"true\" name=\"note\" schema=\"note\"/>\n      </fields>\n      <templates>\n        <template mode=\"any\">/layouts/layout_diff_template.xhtml\n        </template>\n      </templates>\n    </diffBlock>\n\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.service.DiffDisplayService.contrib",
          "name": "org.nuxeo.ecm.diff.service.DiffDisplayService.contrib",
          "requirements": [],
          "resolutionOrder": 181,
          "services": [],
          "startOrder": 194,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.service.DiffDisplayService.contrib\">\n\n  <extension target=\"org.nuxeo.ecm.diff.service.DiffDisplayService\"\n    point=\"diffDefaultDisplay\">\n\n    <diffExcludedFields schema=\"common\" />\n\n  </extension>\n\n  <extension target=\"org.nuxeo.ecm.diff.service.DiffDisplayService\"\n    point=\"diffDisplay\">\n\n    <diffDisplay type=\"Folder\">\n      <diffBlocks>\n        <diffBlock name=\"dublincore\" />\n      </diffBlocks>\n    </diffDisplay>\n\n    <diffDisplay type=\"File\">\n      <diffBlocks>\n        <diffBlock name=\"dublincore\" />\n        <diffBlock name=\"files\" />\n      </diffBlocks>\n    </diffDisplay>\n\n    <diffDisplay type=\"Note\">\n      <diffBlocks>\n        <diffBlock name=\"dublincore\" />\n        <diffBlock name=\"note\" />\n        <diffBlock name=\"files\" />\n      </diffBlocks>\n    </diffDisplay>\n\n  </extension>\n\n  <extension target=\"org.nuxeo.ecm.diff.service.DiffDisplayService\"\n    point=\"diffBlock\">\n\n    <diffBlock name=\"dublincore\">\n      <properties mode=\"any\">\n        <property name=\"label\">label.diffBlock.dublincore</property>\n      </properties>\n      <fields>\n        <field schema=\"dublincore\" name=\"description\" />\n        <!-- Display the \"dam_common\" schema fields in case the DAM package\n          is installed -->\n        <field schema=\"dam_common\" name=\"author\" />\n        <field schema=\"dam_common\" name=\"authoringDate\" />\n        <field schema=\"dublincore\" name=\"nature\" />\n        <field schema=\"dublincore\" name=\"subjects\" />\n        <field schema=\"dublincore\" name=\"rights\" />\n        <field schema=\"dublincore\" name=\"source\" />\n        <field schema=\"dublincore\" name=\"coverage\" />\n        <field schema=\"dublincore\" name=\"created\" />\n        <field schema=\"dublincore\" name=\"modified\" />\n        <field schema=\"dublincore\" name=\"format\" />\n        <field schema=\"dublincore\" name=\"language\" />\n        <field schema=\"dublincore\" name=\"expired\" />\n        <field schema=\"dublincore\" name=\"creator\" />\n        <field schema=\"dublincore\" name=\"contributors\" />\n        <field schema=\"dublincore\" name=\"lastContributor\" />\n      </fields>\n      <templates>\n        <template mode=\"any\">/layouts/layout_diff_template.xhtml\n        </template>\n      </templates>\n    </diffBlock>\n\n    <diffBlock name=\"files\">\n      <properties mode=\"any\">\n        <property name=\"label\">label.diffBlock.files</property>\n      </properties>\n      <fields>\n        <field schema=\"file\" name=\"content\"\n          displayContentDiffLinks=\"true\" />\n        <field schema=\"files\" name=\"files\">\n          <items>\n            <!-- Display the file only, not the filename which is managed\n              by the file widget type -->\n            <item name=\"file\" displayContentDiffLinks=\"true\" />\n          </items>\n        </field>\n      </fields>\n      <templates>\n        <template mode=\"any\">/layouts/layout_diff_template.xhtml\n        </template>\n      </templates>\n    </diffBlock>\n\n    <diffBlock name=\"note\">\n      <properties mode=\"any\">\n        <property name=\"label\">label.diffBlock.note</property>\n      </properties>\n      <fields>\n        <field schema=\"note\" name=\"note\" displayContentDiffLinks=\"true\" />\n      </fields>\n      <templates>\n        <template mode=\"any\">/layouts/layout_diff_template.xhtml\n        </template>\n      </templates>\n    </diffBlock>\n\n  </extension>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/diff-display-contrib.xml",
          "xmlPureComponent": true
        },
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.platform.forms.layout.WebLayoutManager--widgettypes",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.widgets.contrib/Contributions/org.nuxeo.ecm.diff.widgets.contrib--widgettypes",
              "id": "org.nuxeo.ecm.diff.widgets.contrib--widgettypes",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.platform.forms.layout.WebLayoutManager",
                "name": "org.nuxeo.ecm.platform.forms.layout.WebLayoutManager",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"widgettypes\" target=\"org.nuxeo.ecm.platform.forms.layout.WebLayoutManager\">\n\n    <widgetType name=\"version_diff\">\n      <configuration>\n        <title>Diff between live document and a version</title>\n        <sinceVersion>5.7</sinceVersion>\n        <description>\n          <p>\n            The version_diff widget displays difference between the live document and a specific version. If\n            nothing is specified, last version is compared.\n          </p>\n          <p>\n            It accepts the following properties:\n            <ul>\n              <li>\n                versionLabel: the name of the expected label, defautl is \"lastVersion\"\n              </li>\n              <li>\n                propertyXPath: the property XPath, default is \"file:content\"\n              </li>\n              <li>\n                height: the iFrame height, default is \"400px\"\n              </li>\n            </ul>\n          </p>\n        </description>\n        <supportedModes>\n          <mode>view</mode>\n        </supportedModes>\n        <categories>\n          <category>summary</category>\n        </categories>\n      </configuration>\n      <handler-class>\n        org.nuxeo.ecm.platform.forms.layout.facelets.plugins.TemplateWidgetTypeHandler\n      </handler-class>\n      <property name=\"template\">/widgets/version_diff_widget_template.xhtml</property>\n    </widgetType>\n  </extension>"
            },
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.platform.forms.layout.LayoutStore--widgets",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.widgets.contrib/Contributions/org.nuxeo.ecm.diff.widgets.contrib--widgets",
              "id": "org.nuxeo.ecm.diff.widgets.contrib--widgets",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.platform.forms.layout.LayoutStore",
                "name": "org.nuxeo.ecm.platform.forms.layout.LayoutStore",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"widgets\" target=\"org.nuxeo.ecm.platform.forms.layout.LayoutStore\">\n\n    <!-- Generic widgets: name = diff property type, see: org.nuxeo.ecm.diff.model.PropertyType -->\n    <widget name=\"string\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">text</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"boolean\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">checkbox</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"date\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">datetime</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"integer\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">int</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"long\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">int</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"double\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">double</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"content\" type=\"file\">\n      <categories>\n        <category>diff</category>\n      </categories>\n    </widget>\n\n    <widget name=\"complex\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"display\">inline</property>\n        <property name=\"template\">\n          /widgets/complex_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"scalarList\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"display\">inline</property>\n        <property name=\"displayAllItems\">false</property>\n        <property name=\"displayItemIndexes\">true</property>\n        <property name=\"template\">\n          /widgets/list_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"contentList\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"display\">inline</property>\n        <property name=\"displayAllItems\">false</property>\n        <property name=\"displayItemIndexes\">true</property>\n        <property name=\"template\">\n          /widgets/list_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"complexList\" type=\"list\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"display\">inline</property>\n        <property name=\"displayAllItems\">false</property>\n        <property name=\"displayItemIndexes\">true</property>\n        <property name=\"template\">\n          /widgets/list_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"contentDiffLinks\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"template\">\n          /widgets/content_diff_links_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <!-- Specific widgets: name = property xpath -->\n    <widget name=\"dublincore:created\" type=\"datetime\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.created</label>\n      </labels>\n      <translated>true</translated>\n      <properties widgetMode=\"any\">\n        <property name=\"pattern\">#{nxu:basicDateAndTimeFormatter()}\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:modified\" type=\"datetime\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.modified</label>\n      </labels>\n      <translated>true</translated>\n      <properties widgetMode=\"any\">\n        <property name=\"pattern\">#{nxu:basicDateAndTimeFormatter()}\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:issued\" type=\"datetime\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.issueDate</label>\n      </labels>\n      <translated>true</translated>\n      <properties widgetMode=\"any\">\n        <property name=\"pattern\">#{nxu:basicDateAndTimeFormatter()}\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:valid\" type=\"datetime\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.validationDate</label>\n      </labels>\n      <translated>true</translated>\n      <properties widgetMode=\"any\">\n        <property name=\"pattern\">#{nxu:basicDateAndTimeFormatter()}\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:expired\" type=\"datetime\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.expired</label>\n      </labels>\n      <translated>true</translated>\n      <properties widgetMode=\"any\">\n        <property name=\"pattern\">#{nxu:basicDateAndTimeFormatter()}\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"note:note\" type=\"richtext_with_mimetype\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.note.note</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"translatedHtml\">\n          #{noteActions.translateImageLinks(field_0)}\n        </property>\n        <property name=\"cssClass\">note_content_block</property>\n      </properties>\n    </widget>\n\n    <widget name=\"file:content\" type=\"file\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.summary.download.file</label>\n      </labels>\n      <translated>true</translated>\n    </widget>\n\n    <widget name=\"files:files\" type=\"list\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.summary.download.attachments</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"display\">inline</property>\n        <property name=\"displayAllItems\">false</property>\n        <property name=\"displayItemIndexes\">true</property>\n        <property name=\"template\">\n          /widgets/list_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:nature\" type=\"selectOneDirectory\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.nature</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"directoryName\">nature</property>\n        <property name=\"localize\">true</property>\n        <property name=\"ordering\">ordering,label</property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:subjects/item\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.subjects.item</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"template\">/widgets/subjects_item_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:coverage\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.coverage</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"template\">/widgets/coverage_widget.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:contributors/item\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.contributors.item</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"template\">/widgets/contributors_item_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:lastContributor\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.lastContributor</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"template\">\n          /widgets/single_user_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.widgets.contrib",
          "name": "org.nuxeo.ecm.diff.widgets.contrib",
          "requirements": [],
          "resolutionOrder": 182,
          "services": [],
          "startOrder": 198,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.widgets.contrib\">\n\n  <extension target=\"org.nuxeo.ecm.platform.forms.layout.WebLayoutManager\" point=\"widgettypes\">\n\n    <widgetType name=\"version_diff\">\n      <configuration>\n        <title>Diff between live document and a version</title>\n        <sinceVersion>5.7</sinceVersion>\n        <description>\n          <p>\n            The version_diff widget displays difference between the live document and a specific version. If\n            nothing is specified, last version is compared.\n          </p>\n          <p>\n            It accepts the following properties:\n            <ul>\n              <li>\n                versionLabel: the name of the expected label, defautl is \"lastVersion\"\n              </li>\n              <li>\n                propertyXPath: the property XPath, default is \"file:content\"\n              </li>\n              <li>\n                height: the iFrame height, default is \"400px\"\n              </li>\n            </ul>\n          </p>\n        </description>\n        <supportedModes>\n          <mode>view</mode>\n        </supportedModes>\n        <categories>\n          <category>summary</category>\n        </categories>\n      </configuration>\n      <handler-class>\n        org.nuxeo.ecm.platform.forms.layout.facelets.plugins.TemplateWidgetTypeHandler\n      </handler-class>\n      <property name=\"template\">/widgets/version_diff_widget_template.xhtml</property>\n    </widgetType>\n  </extension>\n\n  <extension target=\"org.nuxeo.ecm.platform.forms.layout.LayoutStore\"\n             point=\"widgets\">\n\n    <!-- Generic widgets: name = diff property type, see: org.nuxeo.ecm.diff.model.PropertyType -->\n    <widget name=\"string\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">text</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"boolean\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">checkbox</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"date\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">datetime</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"integer\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">int</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"long\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">int</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"double\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"widgetType\">double</property>\n        <property name=\"template\">\n          /widgets/generic_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"content\" type=\"file\">\n      <categories>\n        <category>diff</category>\n      </categories>\n    </widget>\n\n    <widget name=\"complex\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"display\">inline</property>\n        <property name=\"template\">\n          /widgets/complex_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"scalarList\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"display\">inline</property>\n        <property name=\"displayAllItems\">false</property>\n        <property name=\"displayItemIndexes\">true</property>\n        <property name=\"template\">\n          /widgets/list_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"contentList\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"display\">inline</property>\n        <property name=\"displayAllItems\">false</property>\n        <property name=\"displayItemIndexes\">true</property>\n        <property name=\"template\">\n          /widgets/list_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"complexList\" type=\"list\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"display\">inline</property>\n        <property name=\"displayAllItems\">false</property>\n        <property name=\"displayItemIndexes\">true</property>\n        <property name=\"template\">\n          /widgets/list_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"contentDiffLinks\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <properties mode=\"any\">\n        <property name=\"template\">\n          /widgets/content_diff_links_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <!-- Specific widgets: name = property xpath -->\n    <widget name=\"dublincore:created\" type=\"datetime\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.created</label>\n      </labels>\n      <translated>true</translated>\n      <properties widgetMode=\"any\">\n        <property name=\"pattern\">#{nxu:basicDateAndTimeFormatter()}\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:modified\" type=\"datetime\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.modified</label>\n      </labels>\n      <translated>true</translated>\n      <properties widgetMode=\"any\">\n        <property name=\"pattern\">#{nxu:basicDateAndTimeFormatter()}\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:issued\" type=\"datetime\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.issueDate</label>\n      </labels>\n      <translated>true</translated>\n      <properties widgetMode=\"any\">\n        <property name=\"pattern\">#{nxu:basicDateAndTimeFormatter()}\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:valid\" type=\"datetime\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.validationDate</label>\n      </labels>\n      <translated>true</translated>\n      <properties widgetMode=\"any\">\n        <property name=\"pattern\">#{nxu:basicDateAndTimeFormatter()}\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:expired\" type=\"datetime\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.expired</label>\n      </labels>\n      <translated>true</translated>\n      <properties widgetMode=\"any\">\n        <property name=\"pattern\">#{nxu:basicDateAndTimeFormatter()}\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"note:note\" type=\"richtext_with_mimetype\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.note.note</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"translatedHtml\">\n          #{noteActions.translateImageLinks(field_0)}\n        </property>\n        <property name=\"cssClass\">note_content_block</property>\n      </properties>\n    </widget>\n\n    <widget name=\"file:content\" type=\"file\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.summary.download.file</label>\n      </labels>\n      <translated>true</translated>\n    </widget>\n\n    <widget name=\"files:files\" type=\"list\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.summary.download.attachments</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"display\">inline</property>\n        <property name=\"displayAllItems\">false</property>\n        <property name=\"displayItemIndexes\">true</property>\n        <property name=\"template\">\n          /widgets/list_diff_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:nature\" type=\"selectOneDirectory\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.nature</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"directoryName\">nature</property>\n        <property name=\"localize\">true</property>\n        <property name=\"ordering\">ordering,label</property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:subjects/item\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.subjects.item</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"template\">/widgets/subjects_item_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:coverage\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.coverage</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"template\">/widgets/coverage_widget.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:contributors/item\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.contributors.item</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"template\">/widgets/contributors_item_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n    <widget name=\"dublincore:lastContributor\" type=\"template\">\n      <categories>\n        <category>diff</category>\n      </categories>\n      <labels>\n        <label mode=\"any\">label.dublincore.lastContributor</label>\n      </labels>\n      <translated>true</translated>\n      <properties mode=\"any\">\n        <property name=\"template\">\n          /widgets/single_user_widget_template.xhtml\n        </property>\n      </properties>\n    </widget>\n\n  </extension>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/diff-widgets-contrib.xml",
          "xmlPureComponent": true
        },
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentation": "\n      GET\n      /nuxeo/restAPI/contentDiff/{repo}/{leftDocId}/{rightDocId}/{fieldXPath}/{subPath}?conversionType=(conversionType)&amp;locale={locale}\n    \n",
              "documentationHtml": "<p>\nGET\n/nuxeo/restAPI/contentDiff/{repo}/{leftDocId}/{rightDocId}/{fieldXPath}/{subPath}?conversionType&#61;(conversionType)&amp;locale&#61;{locale}\n</p><p></p>",
              "extensionPoint": "org.nuxeo.ecm.platform.ui.web.restAPI.service.PluggableRestletService--restlets",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.content.restAPI.contrib/Contributions/org.nuxeo.ecm.diff.content.restAPI.contrib--restlets",
              "id": "org.nuxeo.ecm.diff.content.restAPI.contrib--restlets",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.platform.ui.web.restAPI.service.PluggableRestletService",
                "name": "org.nuxeo.ecm.platform.ui.web.restAPI.service.PluggableRestletService",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"restlets\" target=\"org.nuxeo.ecm.platform.ui.web.restAPI.service.PluggableRestletService\">\n\n    <documentation>\n      GET\n      /nuxeo/restAPI/contentDiff/{repo}/{leftDocId}/{rightDocId}/{fieldXPath}/{subPath}?conversionType=(conversionType)&amp;locale={locale}\n    </documentation>\n\n    <restletPlugin class=\"org.nuxeo.ecm.diff.content.restlet.ContentDiffRestlet\" enabled=\"true\" name=\"contentDiff\" useSeam=\"false\">\n      <urlPatterns>\n        <urlPattern>/contentDiff/{repo}/{leftDocId}/{rightDocId}/{fieldXPath}/\n        </urlPattern>\n        <urlPattern>/contentDiff/{repo}/{leftDocId}/{rightDocId}/{fieldXPath}/{subPath}\n        </urlPattern>\n      </urlPatterns>\n    </restletPlugin>\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.content.restAPI.contrib",
          "name": "org.nuxeo.ecm.diff.content.restAPI.contrib",
          "requirements": [],
          "resolutionOrder": 183,
          "services": [],
          "startOrder": 193,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.content.restAPI.contrib\">\n\n  <extension\n    target=\"org.nuxeo.ecm.platform.ui.web.restAPI.service.PluggableRestletService\"\n    point=\"restlets\">\n\n    <documentation>\n      GET\n      /nuxeo/restAPI/contentDiff/{repo}/{leftDocId}/{rightDocId}/{fieldXPath}/{subPath}?conversionType=(conversionType)&amp;locale={locale}\n    </documentation>\n\n    <restletPlugin name=\"contentDiff\"\n      class=\"org.nuxeo.ecm.diff.content.restlet.ContentDiffRestlet\"\n      enabled=\"true\" useSeam=\"false\">\n      <urlPatterns>\n        <urlPattern>/contentDiff/{repo}/{leftDocId}/{rightDocId}/{fieldXPath}/\n        </urlPattern>\n        <urlPattern>/contentDiff/{repo}/{leftDocId}/{rightDocId}/{fieldXPath}/{subPath}\n        </urlPattern>\n      </urlPatterns>\n    </restletPlugin>\n  </extension>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-restAPI-contrib.xml",
          "xmlPureComponent": true
        },
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.theme.styling.service--pages",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.theme/Contributions/org.nuxeo.ecm.diff.theme--pages",
              "id": "org.nuxeo.ecm.diff.theme--pages",
              "registrationOrder": 2,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.theme.styling.service",
                "name": "org.nuxeo.theme.styling.service",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"pages\" target=\"org.nuxeo.theme.styling.service\">\n\n    <page name=\"galaxy/default\">\n      <resources append=\"true\">\n        <resource>diff.css</resource>\n      </resources>\n    </page>\n\n  </extension>"
            },
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.platform.WebResources--resources",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.theme/Contributions/org.nuxeo.ecm.diff.theme--resources",
              "id": "org.nuxeo.ecm.diff.theme--resources",
              "registrationOrder": 7,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.platform.WebResources",
                "name": "org.nuxeo.ecm.platform.WebResources",
                "type": "service"
              },
              "version": "2023.25.10",
              "xml": "<extension point=\"resources\" target=\"org.nuxeo.ecm.platform.WebResources\">\n\n    <resource name=\"diff.css\">\n      <path>themes/css/diff_result.css</path>\n    </resource>\n\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf/org.nuxeo.ecm.diff.theme",
          "name": "org.nuxeo.ecm.diff.theme",
          "requirements": [
            "org.nuxeo.theme.nuxeo.webapp"
          ],
          "resolutionOrder": 663,
          "services": [],
          "startOrder": 197,
          "version": "2023.25.10",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.theme\">\n\n  <require>org.nuxeo.theme.nuxeo.webapp</require>\n\n  <!-- Theme pages -->\n  <extension target=\"org.nuxeo.theme.styling.service\" point=\"pages\">\n\n    <page name=\"galaxy/default\">\n      <resources append=\"true\">\n        <resource>diff.css</resource>\n      </resources>\n    </page>\n\n  </extension>\n\n  <!-- Styles -->\n  <extension target=\"org.nuxeo.ecm.platform.WebResources\" point=\"resources\">\n\n    <resource name=\"diff.css\">\n      <path>themes/css/diff_result.css</path>\n    </resource>\n\n  </extension>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/diff-theme-contrib.xml",
          "xmlPureComponent": true
        }
      ],
      "fileName": "nuxeo-diff-jsf-2023.25.10.jar",
      "groupId": "org.nuxeo.ecm",
      "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.jsf",
      "id": "org.nuxeo.diff.jsf",
      "location": "",
      "manifest": "Manifest-Version: 1.0\r\nArchiver-Version: Plexus Archiver\r\nCreated-By: Apache Maven 3.9.6\r\nBuilt-By: root\r\nBuild-Jdk: 17.0.14\r\nBundle-ManifestVersion: 2\r\nBundle-Version: 5.6\r\nBundle-ActivationPolicy: lazy\r\nBundle-ClassPath: .\r\nBundle-Name: org.nuxeo.diff.jsf\r\nBundle-RequiredExecutionEnvironment: JavaSE-1.6\r\nBundle-Vendor: Nuxeo\r\nBundle-SymbolicName: org.nuxeo.diff.jsf;singleton:=true\r\nNuxeo-Component: OSGI-INF/diff-actions-contrib.xml,OSGI-INF/diff-display\r\n -service.xml,OSGI-INF/diff-display-contrib.xml,OSGI-INF/diff-widgets-co\r\n ntrib.xml,OSGI-INF/diff-theme-contrib.xml,OSGI-INF/content-diff-restAPI\r\n -contrib.xml\r\n\r\n",
      "maxResolutionOrder": 663,
      "minResolutionOrder": 179,
      "packages": [
        "nuxeo-diff"
      ],
      "requirements": [],
      "version": "2023.25.10"
    }
  ],
  "creationDate": 1738062879135,
  "key": "Nuxeo Platform-2023.25",
  "name": "Nuxeo Platform",
  "operations": [],
  "packages": [
    {
      "@type": "NXPackage",
      "bundles": [
        "org.nuxeo.diff.content",
        "org.nuxeo.diff.core",
        "org.nuxeo.diff.jsf"
      ],
      "conflicts": [],
      "dependencies": [
        "nuxeo-jsf-ui"
      ],
      "hierarchyPath": "/nuxeo-diff-2023.25.10",
      "id": "nuxeo-diff-2023.25.10",
      "name": "nuxeo-diff",
      "optionalDependencies": [],
      "packageType": "addon",
      "title": "Nuxeo Diff",
      "version": "2023.25.10"
    }
  ],
  "pluginSnapshots": {},
  "releaseDate": 1738062879135,
  "version": "2023.25"
}